繁体   English   中英

如何在Java中正确使用volatile

[英]How to use volatile correctly in Java

我正在研究Java Thread,当我分析从例8.3.1.4修改的以下代码时,关键字volatile会让我感到困惑

public class Volatile {
    public static void main(String[] args){
        MyRunnable1 myRunnable1 = new MyRunnable1();
        MyRunnable2 myRunnable2 = new MyRunnable2();
        Thread t1 = new Thread(myRunnable1);
        Thread t2 = new Thread(myRunnable2);

        t1.start();
        t2.start();
    }
}

class MyRunnable1 implements Runnable{
    public void run(){
        while(true){
            Test1.one();
        }
    }
}
class MyRunnable2 implements Runnable{
    public void run(){
        while(true){
            Test1.two();
        }
    }
}

class Test1{
    static volatile int i = 0;
    static volatile int j = 0;
    static void one(){
        i ++;
        j ++;
    }

    static void two(){
        System.out.println("i = " + i  + " j = " + j);
    }
}

输出段:

i = 60778110 j = 60778116
i = 60778402 j = 60778407
i = 60778630 j = 60778636
i = 60779062 j = 60779079
i = 60779492 j = 60779497
i = 60779784 j = 60779789
i = 60780161 j = 60780169
i = 60780625 j = 60780632
i = 60780936 j = 60780942

我的想法是,由于volatilei ++发生在j ++之前,它们的初始值为零,修改后的值将立即刷新到主存储器,因此i线程t2看到的任何时候都应该大于j 但是输出显示i总是低于j

然后我修改这two函数如下:

static void two(){
    System.out.println("j = " + j  + " i = " + i);
}

的变化是, j输出之前i ,然后输出段如下:

j = 47324409 i = 47324412
j = 47324587 i = 47324593
j = 47324808 i = 47324813
j = 47324991 i = 47324996
j = 47325193 i = 47325196
j = 47325347 i = 47325353

令我惊讶的是, j总是低于i

我的想法是j是较低的,因为它首先被连接,并且在i连接一段时间之后,在时间间隔期间, one函数执行导致i增加。

所以第一个连接值将低于第二个连接值,是不是? 提前致谢!

你猜对了。 不同之处在于println调用的参数分为3个步骤:

  1. 构建字符串s =“i =”+ i
  2. 构建字符串s = s +“j =”
  3. 构建字符串s = s + j

在Runnable2执行此操作时,特别是在step1之后和最终打印之前,Runnable2正忙于递增值。 这会导致你看到的行为。

这不是挥发性的问题。 如果希望i和j同步,则必须同步Test1类的方法。

实际上, volatile只是阻止线程缓存一个值,而是强制“直写”和“读取”:如果一个线程缓存一个变量并由另一个线程更新,那么第一个线程的值可能永远不会改变,因为Java的缓存策略,不需要刷新其缓存。

因此,每当您有多个线程访问和更改原始资源(如int,boolean或引用类型引用值本身)时,您应该使用volatile。

这本身并不意味着volatile实际上使变量访问线程安全!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM