【发布时间】:2016-09-09 19:26:19
【问题描述】:
执行以下 sn-p 时,我看到结果正在正确且唯一地递增,但是它们被无序打印(如下所示):
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();
}
}
}
示例结果:
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
是不是因为:
代码有问题(如果有,如何修复它以强制排序)?
这是不是原子的正确行为,因为在设计上它们不保证执行顺序,而只保证无锁并发?
这里还有其他工作吗?
TIA。
为了解决我对下面的 cmets 的困惑 - 如果我仍然需要使用同步来查看下面发生的情况,为什么我首先需要 Atomics?
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;
}
}
}
}
};
【问题讨论】:
-
index取值的顺序不一定是println调用发生的顺序。compareAndSet是原子的;compareAndSet-and-println 不是。 -
它是#2。原子变量强制更新的原子性和更新的内存可见性。它们与订购无关。
-
@4castle: 那么,这是否意味着原子 CAS 真的对我没有任何好处,因为我仍然需要通过
println同步才能看到我感兴趣的内容?要不然是啥?代码示例表示赞赏。 -
您必须同步包含
compareAndSet()和println()的块。如果没有同步,另一个线程可能会在两者之间进行两次调用,因此会乱序打印。当然,如果你进行同步,你就不需要原子了。 -
您可能对incrementAndGet函数感兴趣。
标签: java concurrency atomic java.util.concurrent java-memory-model