正如我所知道的,在尝试从多个线程执行相同的操作时,Java并发API的原子类上的操作是一个接一个地执行的,下面的程序的输出对我来说似乎不一致。
public class VisitorCounterAtomic {
private AtomicInteger visitorCount = new AtomicInteger(0);
public void visitAndPrint() {
System.out.println("Total Visitors: " + visitorCount.incrementAndGet());
}
public static void main(String... args) {
ExecutorService service = null;
VisitorCounterAtomic counter = new VisitorCounterAtomic();
try {
service = Executors.newFixedThreadPool(20);
for (int i = 0; i < 10; i++)
service.submit(() -> counter.visitAndPrint());
} finally {
if (null != service) service.shutdown();
}
}
}输出:
Total Visitors: 1
Total Visitors: 4
Total Visitors: 2
Total Visitors: 5
Total Visitors: 3
Total Visitors: 6
Total Visitors: 7
Total Visitors: 8
Total Visitors: 9
Total Visitors: 10我的预期输出:
Total Visitors: 1
Total Visitors: 2
Total Visitors: 3
Total Visitors: 4
Total Visitors: 5
Total Visitors: 6
Total Visitors: 7
Total Visitors: 8
Total Visitors: 9
Total Visitors: 10我知道我可以使用synchronization块生成我的预期输出,但我需要解释为什么不使用原子变量生成预期的输出。
我的推理就像--不管线程执行的顺序如何,它都会在另一个线程增加并打印原子变量的值之前增加和打印。
发布于 2018-04-22 17:00:25
实际订单与AtomicInteger没有任何关系。
AtomicInteger保证可以原子地更新该值。它不能保证线程是按顺序执行的。
实际上,ExecutorService实例以异步方式处理任务。
因此,您无法获得可预测的任务完成顺序。
实际上,在执行incrementAndGet()和println()之间有一个竞争条件。
public void visitAndPrint() {
System.out.println("Total Visitors: " + visitorCount.incrementAndGet());
}例如,假设:
visitorCount.incrementAndGet() (计数器= 1),但不执行println()visitorCount.incrementAndGet() (计数器= 2)和println()println()结果:
访客总数:2 访客总数:1
通过同步该方法,您应该有预期的顺序:
public synchronized void visitAndPrint() {
System.out.println("Total Visitors: " + visitorCount.incrementAndGet());
}发布于 2018-04-22 17:33:43
AtomicInteger类提供原子操作。这意味着它将确保每次只有一个线程对该变量执行操作。它在本质上也是非阻塞。在您的代码中,多个线程同时运行,所以AtomicInteger做得很好,但是哪个线程将首先完成它的任务,而不是依赖于
要解决这个问题,可以使用同步函数来解决这个问题。
https://stackoverflow.com/questions/49968404
复制相似问题