-2
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通过i从被AtomicInteger调用的count. 然后每个Thread等待被CountDownLatch调用cdl1(当最后一个Thread到达闩锁时,所有Threads都被释放)。当闩锁被释放时,每个线程都会尝试将它们的受限i值分配给共享的volatile,int称为bar

我希望Thread除一个之外的每个都打印出“Bar not equal to i”,但每个Thread打印出“Bar equal to i”。呃,volatile如果不是这个,wtf 确实会这样做?

这是一个故意的意图,每个Thread尝试bar在完全相同的时间设置值。

编辑:

根据答案,将代码更改为:

...
bar = i;
try {
    Thread.sleep(0);
} catch(InterruptedException e) {
    e.printStackTrace();
}
...

确保在变量的设置和读取之间浪费一点时间。

现在,Bar 的相同/不同值的打印是 50/50。

4

5 回答 5

8

JVM 决定线程何时运行,而不是您。如果感觉就像握住其中一个闩锁刚刚释放的另一个 10 毫秒,只是因为,它可以做到这一点。在闩锁释放后,它们仍然需要等待轮到它们执行。除非您在 25 核计算机上运行它,否则它们并非都在机器内部“同时”附近的任何地方分配 bar。由于您所做的只是几个原始操作,因此其中一个操作在下一个发布之前不会在其时间片内完成是极不可能的!

于 2010-05-07T23:49:38.107 回答
2

它不是。你在滥用它。Herb Sutter在这里有一篇很棒的文章更详细地解释了它。

基本思想是volatile使变量不可优化。它不会使它们成为线程安全的。

于 2010-05-08T00:01:31.063 回答
2

要回答'WTF volatile 真的会做吗?':

volatile 是关于可见性的。在 Java 的线程模型中,如果线程 A 写入常规共享字段,则无法保证线程 B 会看到A 写入的值,除非线程以某种方式同步。volatile 是同步机制之一。

与非易失性字段不同,当线程 A 写入易失性字段并且线程 B 稍后读取它时,B 可以保证看到新值而不是旧版本。

(实际上 volatile 做得更多——线程 B 不仅会看到该字段的新值,还会看到 A 在设置 volatile 变量之前写入的所有其他内容。它建立了发生前的关系)。

于 2010-05-08T00:05:20.057 回答
1

您应该做的是将您的实例替换volatile intAtomicInteger. 见这里

于 2010-05-08T00:01:59.813 回答
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” 。

于 2010-05-07T23:49:12.320 回答