volatile关键字似乎没用?

时间:2010-05-07 23:43:52

标签: java concurrency volatile

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值分配给共享的Threadsi,称为volatile

我希望每个int除了一个打印出“Bar not equal to i”,但每个bar打印“Bar等于i”。呃,wtf确实Thread如果不是这样的话呢?

故意暗示每个Thread尝试在同一时间设置volatile的值。

编辑:

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

Thread

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

现在,对于Bar,打印的相同/不同值为50/50。

5 个答案:

答案 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”就像你期望的那样。