使用AtomicInteger作为静态共享计数器

Jus*_*les 4 java multithreading synchronization

为了通过Java了解同步,我只是搞乱一些简单的事情,比如创建线程之间共享的计数器.

我遇到的问题是我无法弄清楚如何在100%的时间内依次打印计数器.

int counterValue = this.counter.incrementAndGet();
System.out.println(this.threadName + ": " + counterValue);
Run Code Online (Sandbox Code Playgroud)

上面增加AtomicInteger counter,获取新值,并将其打印到由负责该更新的线程名称标识的控制台.当incrementAndGet()打印当前线程的更新值之前,该方法似乎导致JVM上下文切换到另一个线程以进行更新时,会出现问题.这意味着在线程返回执行状态之前,该值会增加但不会打印.在查看此示例输出时,这很明显:

Thread 3: 4034
Thread 3: 4035
Thread 3: 4036
Thread 1: 3944
Thread 1: 4037
Thread 1: 4039
Thread 1: 4040
Thread 2: 3863
Thread 1: 4041
Thread 1: 4043
Run Code Online (Sandbox Code Playgroud)

您可以看到,当执行返回到线程1时,它会打印其值并继续更新.线程2也是如此.

我有一种感觉,我错过了一些非常明显的东西.

Gra*_*ray 7

在打印当前线程的更新值之前,似乎incrementAndGet()方法导致JVM上下文切换到另一个线程以进行更新时,会出现问题

这种情况通常会在这些情况下发生.虽然AtomicInteger柜台被适当增加,没有什么可以阻止Thread 2被换出增量发生,之前println被调用.

int counterValue = this.counter.incrementAndGet();
// there is nothing stopping a context switch here
System.out.println(this.threadName + ": " + counterValue);
Run Code Online (Sandbox Code Playgroud)

如果您想要打印的"反顺序100%的时间"你将不得不围绕增量都锁同步println电话.当然,如果你这样做,那就AtomicInteger浪费了.

synchronized (counter) {
    System.out.println(this.threadName + ": " + counter.incrementAndGet());
}
Run Code Online (Sandbox Code Playgroud)

如果你编辑你的问题来解释为什么你需要输出是顺序的,也许有一个没有这种竞争条件的更好的解决方案.