When executing the following snippet I'm seeing that results are getting properly and uniquely incremented however they are printed out of order (as shown below):
import java.util.concurrent.atomic.AtomicInteger;
public class Atomics {
private AtomicInteger index = new AtomicInteger(0);
public static void main(String [] args) {
new Atomics().updateIndexViaCAS();
}
private void updateIndexViaCAS() {
Runnable target = () -> {
for(int i = 0; i<10;i++) {
cas:
while (true) {
int oldValue = index.get();
int newValue = oldValue + 1;
if(index.compareAndSet(oldValue, newValue)) {
System.out.println(Thread.currentThread() + ": "+newValue); //order is not guaranteed?
break cas;
}
}
}
};
/*Runnable target = () -> {
for (int i = 0; i < 10; i++) {
int oldValue = index.get();
int newValue = oldValue + 1;
do {
oldValue = index.get();
} while (!index.compareAndSet(oldValue, newValue));
System.out.println(Thread.currentThread() + ": "+newValue);
}
};*/
for(int t=0; t<2;t++) {
Thread th = new Thread(target);
th.start();
}
}
}
Sample Results:
Thread[Thread-0,5,main]: 1
Thread[Thread-0,5,main]: 3
Thread[Thread-0,5,main]: 4
Thread[Thread-0,5,main]: 5
Thread[Thread-0,5,main]: 6
Thread[Thread-1,5,main]: 2 <-- out of order
Thread[Thread-0,5,main]: 7
Thread[Thread-0,5,main]: 9
Thread[Thread-0,5,main]: 10
Thread[Thread-0,5,main]: 11
Thread[Thread-0,5,main]: 12
Thread[Thread-1,5,main]: 8 <-- out of order
Thread[Thread-1,5,main]: 13
Thread[Thread-1,5,main]: 14
Thread[Thread-1,5,main]: 15
Thread[Thread-1,5,main]: 16
Thread[Thread-1,5,main]: 17
Thread[Thread-1,5,main]: 18
Thread[Thread-1,5,main]: 19
Thread[Thread-1,5,main]: 20
Is it because:
There's something wrong with the code (and if so how to fix it to enforce ordering)?
Is it the proper behavior of atomics because by design they do not guarantee the execution order but only guarantee lockless concurrency?
Something else at work here?
TIA.
To address my confusion with the comments below - why would I need the Atomics in the first place if I still need to use synchronization to view what is going on like below?
Runnable target = () -> {
for (int i = 0; i < 10; i++) {
cas: while (true) {
synchronized (mutex) {
int oldValue = index.get();
int newValue = oldValue + 1;
if (index.compareAndSet(oldValue, newValue)) {
System.out.println(Thread.currentThread() + ": "
+ newValue); // order is not guaranteed?
break cas;
}
}
}
}
};
答案 0 :(得分:1)
无法保证代码如何交错。在你的情况下,我认为混淆是循环不是作为一个单元执行,但可以以任何方式交错。考虑线程1在执行System.out.println(Thread.currentThread() + ": " + newValue)
之前停止,其中newValue
从0
增加到1
,因此尚未打印任何内容。然后,线程2可以从1
增加到2
并在另一个线程之前打印其输出。这将导致首先打印更大的数字。
另外,请记住System.out.println
在System.out
上进行同步。这就是为什么你总是以正确的顺序观察大块的印刷品。一个线程可能会发现System.out
被锁定并在恢复其活动之前暂停其活动。