import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
public class Main implements Runnable {
private final CountDownLatch cdl1 = new CountDownLatch(NUM_THREADS);
private volatile int bar = 0;
private AtomicInteger count = new AtomicInteger(0);
private static final int NUM_THREADS = 25;
public static void main(String[] args) {
Main main = new Main();
for(int i = 0; i < NUM_THREADS; i++)
new Thread(main).start();
}
public void run() {
int i = count.incrementAndGet();
cdl1.countDown();
try {
cdl1.await();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
bar = i;
if(bar != i)
System.out.println("Bar not equal to i");
else
System.out.println("Bar equal to i");
}
}
每个Thread
都会进入run方法,并通过从名为int
的{{1}}获取值来获取唯一的线程限制i
变量AtomicInteger
。然后每个count
等待名为Thread
的{{1}}(当最后CountDownLatch
到达锁定时,所有cdl1
都被释放)。释放锁存器后,每个线程都会尝试将其受限Thread
值分配给共享的Threads
,i
,称为volatile
。
我希望每个int
除了一个打印出“Bar not equal to i”,但每个bar
打印“Bar等于i”。呃,wtf确实Thread
如果不是这样的话呢?
故意暗示每个Thread
尝试在同一时间设置volatile
的值。
编辑:
根据答案,将代码更改为:
Thread
确保在设置和读取变量之间浪费一点时间。
现在,对于Bar,打印的相同/不同值为50/50。
答案 0 :(得分:8)
JVM决定线程何时运行,而不是你。如果它感觉像握着其中一个闩锁刚刚释放了10ms的那个,只是因为它可以做到这一点。在闩锁释放后,他们仍然需要等待轮到他们执行。除非你在一台25核计算机上运行它,否则它们并不是在机器内“同时”附近的任何地方分配条形码。由于您所做的只是一些原始操作,因此在下一个释放之前,其中一个不可能在其时间片内完成!
答案 1 :(得分:2)
不是。你在滥用它。 Herb Sutter撰写了一篇很棒的文章here,更详细地解释了它。
基本思想是volatile
使变量无法优化。它不会使它们的线程安全。
答案 2 :(得分:2)
回答'WTF确实挥发性吗?':
volatile是关于可见性的。在Java的线程模型中,如果线程A写入常规共享字段,则无法保证线程B 永远 看到A写入的值,除非线程以某种方式同步。 volatile是同步机制之一。
与非易失性字段不同,当线程A写入易失性字段并且线程B稍后读取它时,B保证看到新值而不是旧版本。
(实际上volatile实际上更多 - 线程B不仅会看到字段的新值,而且还会在设置volatile变量之前看到A写的所有其他内容。它建立了之前发生过的关系。)
答案 3 :(得分:1)
您应该做的是将volatile int
的实例替换为AtomicInteger
。请参阅here。
答案 4 :(得分:0)
我认为你打算写这个:
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
public class Main implements Runnable {
private final CountDownLatch cdl1 = new CountDownLatch(NUM_THREADS);
private volatile int bar = 0;
private AtomicInteger count = new AtomicInteger(0);
private static final int NUM_THREADS = 25;
public static void main(String[] args) {
Main main = new Main();
for(int i = 0; i < NUM_THREADS; i++)
new Thread(main).start();
}
public void run() {
int i = count.incrementAndGet();
bar = i;
cdl1.countDown();
try {
cdl1.await();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
if(bar != i)
System.out.println("Bar not equal to i");
else
System.out.println("Bar equal to i");
}
}
打印“Bar not equal to i”就像你期望的那样。