在java中易失性

mak*_*aks 12 java concurrency volatile

据我所知,在易失性读取之前发生了易失性写入 ,所以我们总是会在volatile变量中看到最新的数据.我的问题基本上涉及到之前发生的术语以及它发生在哪里?我写了一段代码来澄清我的问题.

class Test {
   volatile int a;
   public static void main(String ... args) {
     final Test t = new Test();
     new Thread(new Runnable(){
        @Override
        public void run() {
            Thread.sleep(3000);
            t.a = 10;
        }
     }).start();
     new Thread(new Runnable(){
        @Override
        public void run() {
            System.out.println("Value " + t.a);
        }
     }).start();
   }
}
Run Code Online (Sandbox Code Playgroud)

(为清楚起见,省略了try catch块)

在这种情况下,我总是看到要在控制台上打印的值0.没有Thread.sleep(3000);我总是看到值10.这是发生在之前关系的情况还是打印'值10'因为线程1开始早一点线程2?

很高兴看到每个程序启动时带有和不带volatile变量的代码行为都不同的例子,因为上面代码的结果仅取决于(至少在我的情况下)线程顺序和线程休眠.

JB *_*zet 9

您会看到值0,因为在写入之前执行了读取操作.并且您看到值10,因为写入在读取之前执行.

如果您希望测试具有更多不可预测的输出,则应该让两个线程等待CountDownLatch,以使它们同时启动:

final CountDownLatch latch = new CountDownLatch(1);
new Thread(new Runnable(){
    @Override
    public void run() {
        try {
            latch.await();
            t.a = 10;
        }
        catch (InterruptedException e) {
            // end the thread
        }
    }
 }).start();
 new Thread(new Runnable(){
    @Override
    public void run() {
        try {
            latch.await();
            System.out.println("Value " + t.a);
        }
        catch (InterruptedException e) {
            // end the thread
        }
    }
 }).start();
 Thread.sleep(321); // go
 latch.countDown();
Run Code Online (Sandbox Code Playgroud)

  • @maks这个例子的问题是它实际上并没有证明`volatile'之前发生的关系.挥发性在这里没有任何作用.你需要让第一个线程设置`ta`然后`countDown`而另一个线程等待`latch.await()`这会在CountDownLatch上的两个线程之间创建一个before-before关系. (3认同)

Joh*_*int 5

之前发生的事情与写入在任何后续读取之前发生有关.如果写没有发生,那么真的没有关系.由于写线程处于休眠状态,因此在写入发生之前执行读取.

要观察行动中的关系,你可以有两个变量,一个是volatile,另一个是volatile.根据JMM,它表示在易失性写入发生之前,在易失性读取之前写入非易失性变量.

例如

volatile int a = 0;
int b = 0;
Run Code Online (Sandbox Code Playgroud)

线程1:

b = 10;
a = 1;
Run Code Online (Sandbox Code Playgroud)

线程2:

while(a != 1);
if(b != 10)
  throw new IllegalStateException();
Run Code Online (Sandbox Code Playgroud)

Java内存模型表示b应始终等于10,因为非易失性存储发生在volatile存储之前.并且所有写入都发生在易失性存储发生之前的一个线程中 - 在所有后续的易失性加载之前.