Using AtomicInteger as a static shared counter

巧了我就是萌 提交于 2019-12-05 17:19:31

The problem occurs when it appears that the incrementAndGet() method is causing the JVM to context switch to another thread for its updates before printing the current thread's updated value

This is a race condition that often can happen in these situations. Although the AtomicInteger counters are being incremented properly, there is nothing to stop Thread 2 from being swapped out after the increment happens and before the println is called.

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

If you want to print the "counter sequentially 100% of the time" you are going to have to synchronize on a lock around both the increment and the println call. Of course if you do that then the AtomicInteger is wasted.

synchronized (counter) {
    System.out.println(this.threadName + ": " + counter.incrementAndGet());
}

If you edit your question to explain why you need the output to be sequential maybe there is a better solution that doesn't have this race condition.

You need to synchronize the whole construction for that:

synchronized(this) {    
   int counterValue = this.counter.incrementAndGet();
   System.out.println(this.threadName + ": " + counterValue);
}

In this case, though, you don't have to use AtomicInteger. Plain int would work (counter++).

To print sequentially, the incAndGet and the println must both be in a critical region, a piece of code only one thread may enter, the others being blocked. Realisable with a binary semaphore, for instance, like java synchronized.

You could turn things on the head, and have one thread incrementing a counter and printing it. Other threads may in a "critical region" take only one after another the counter. That would be more efficient, as critical regions should remain small and preferable do no I/O.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!