Java-通过返回新值实现线程安全集方法
我正在尝试为AtomicInteger实施设定方法并返回新值。不幸的是,这涉及比赛条件。我认为这是因为两个语句this.counter.set(newValue);
和返回this.counter.get();
如果我让它们一起运行,则不是原子。我还尝试使用同步块,但也无济于事。您知道如何设置一个新值并以原子方法返回值?由于原因,我不能更改方法签名。
这是设定方法应该是:
import java.util.concurrent.atomic.AtomicInteger;
import util.Incrementer;
public class AtomicIncrementer implements Incrementer {
private AtomicInteger counter = new AtomicInteger();
private int startValue;
public AtomicIncrementer(int startValue) {
this.startValue = startValue;
this.counter.set(startValue);
}
@Override
public int setValue(int newValue) {
// TODO: implement, do not change method the signature!
synchronized (this.counter) {
this.counter.set(newValue);
return this.counter.get();
}
}
}
我正在进行此测试的课程:
package incrementer;
import impl.AtomicIncrementer;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class TestAtomicIncrementer {
private final int defaultThreadPoolSize = 8;
private final int defaultThreadCount = 24;
@Test
void testSetValue() {
int newValue = (int) (Math.random() * 100);
AtomicIncrementer inc = new AtomicIncrementer(0);
ExecutorService executor = Executors.newFixedThreadPool(defaultThreadPoolSize);
for(int i = 0; i < defaultThreadCount; i++) {
executor.submit(() -> {
for(int j = 0; j < 1000; j++) {
inc.increment();
}
return null;
});
}
try {
assertEquals(newValue, executor.submit(() -> inc.setValue(newValue)).get());
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
try {
executor.shutdown();
assertTrue(executor.awaitTermination(60, TimeUnit.SECONDS));
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
inc.setValue(newValue);
assertEquals(newValue, inc.getValue());
}
private List<Future<Integer>> executeOperation(Callable<Integer> op, AtomicIncrementer inc, int threadCount, int threadPoolSize) {
ExecutorService executor = Executors.newFixedThreadPool(threadPoolSize);
List<Callable<Integer>> ops = new ArrayList<>(threadCount);
for(int i = 0; i < threadCount; i++) {
ops.add(op);
}
try {
return executor.invokeAll(ops);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
有时是测试成功,有时不是,这对我来说似乎是一个种族条件问题。
你怎么认为?
I am trying to implement a set method for an AtomicInteger and return the new value. Unfortunately, it comes to race conditions. I think it is because the two statements this.counter.set(newValue);
and return this.counter.get();
are not Atomic if I let them run together. I also tried to use a synchronized block, but it did not help either. Do you know how I can set a new Value and return the value in an atomic method? For reasons, I can't change the method signature.
Here is the Class where the set method should be:
import java.util.concurrent.atomic.AtomicInteger;
import util.Incrementer;
public class AtomicIncrementer implements Incrementer {
private AtomicInteger counter = new AtomicInteger();
private int startValue;
public AtomicIncrementer(int startValue) {
this.startValue = startValue;
this.counter.set(startValue);
}
@Override
public int setValue(int newValue) {
// TODO: implement, do not change method the signature!
synchronized (this.counter) {
this.counter.set(newValue);
return this.counter.get();
}
}
}
I am running this test:
package incrementer;
import impl.AtomicIncrementer;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class TestAtomicIncrementer {
private final int defaultThreadPoolSize = 8;
private final int defaultThreadCount = 24;
@Test
void testSetValue() {
int newValue = (int) (Math.random() * 100);
AtomicIncrementer inc = new AtomicIncrementer(0);
ExecutorService executor = Executors.newFixedThreadPool(defaultThreadPoolSize);
for(int i = 0; i < defaultThreadCount; i++) {
executor.submit(() -> {
for(int j = 0; j < 1000; j++) {
inc.increment();
}
return null;
});
}
try {
assertEquals(newValue, executor.submit(() -> inc.setValue(newValue)).get());
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
try {
executor.shutdown();
assertTrue(executor.awaitTermination(60, TimeUnit.SECONDS));
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
inc.setValue(newValue);
assertEquals(newValue, inc.getValue());
}
private List<Future<Integer>> executeOperation(Callable<Integer> op, AtomicIncrementer inc, int threadCount, int threadPoolSize) {
ExecutorService executor = Executors.newFixedThreadPool(threadPoolSize);
List<Callable<Integer>> ops = new ArrayList<>(threadCount);
for(int i = 0; i < threadCount; i++) {
ops.add(op);
}
try {
return executor.invokeAll(ops);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
Sometimes the test success and sometimes not, which seems like a race condition Problem for me.
What do you think?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论