2 learningcsdn learningcsdn 于 2016.02.29 17:50 提问

volatile 关键字 作用结果求解惑
 public class testVolatile {
    private  int i = 0;

    // a线程调用
    public void foo1() {
        try {
            while (true) {
                Thread.sleep(10);
                System.out.println("第一个:" + i);
                i++;
            }
        } catch (InterruptedException e) {
            // not to do;
        }
    }

    // b线程调用
    public void foo2() {
        try {
            while (true) {
                Thread.sleep(10);
                System.out.println("第二个:" + i);
            }
        } catch (InterruptedException e) {
            // not to do;
        }

    }

    public static void main(String[] args) {

        final testVolatile test = new testVolatile();
        // 线程1
        new Thread() {
            public void run() {
                test.foo1();
            }
        }.start();
        // 线程2
        new Thread() {
            public void run() {
                test.foo2();
            }
        }.start();

    }
}

输出结果如下:

 第一个:0
第二个:1
第一个:1
第二个:2
第一个:2
第二个:3
第一个:3
第二个:4
第一个:4
第二个:5
第一个:5
第二个:6
第一个:6
第二个:7
第一个:7
第二个:8
第一个:8
第二个:9
第一个:9
第二个:10
第一个:10

变量i增加volatile 关键字后如下

 第二个:0
第一个:0
第二个:1
第一个:1
第二个:2
第一个:2
第二个:3
第一个:3
第二个:4
第一个:4
第二个:5
第一个:5
第二个:6
第一个:6
第二个:7
第一个:7
第二个:8
第一个:8
第二个:9
第一个:9
第二个:10

求高人指点,变量 i 没有增加 volatile 关键字时,第二个输出为什么会随着第一个i 的变化而变化?

2个回答

wojiushiwo945you
wojiushiwo945you   Ds   Rxr 2016.02.29 18:43
已采纳

你需要了解volatile关键字作用,一个定义为volatile的变量,它将具备两种性质:第一是保证此变量对所有线程的可见性,即当一个线程修改了这个变量后,这个新值对于其他线程来说是立即可见的。第二就是保证不进行指令重排序。
所以,你没有添加volatile关键字,多线程同时修改变量可能某个线程读到的数据不是最新值,即你的第一个输出结果体现了某个时刻线程1,2同时读到了数值1时,此时线程2可能已经修改了变量。所以导致了不正确的结果。

learningcsdn
learningcsdn 不好意思,回车按多了,,,对于你说的第二不能进行指令重排序,不是很清楚,能进一步解释下吗?
接近 2 年之前 回复
learningcsdn
learningcsdn 嗯嗯,感谢回答,今天又学习了下,总结来说就是volatile关键字会把一个线程对其的修改立刻回写到内存,并使其它线程的缓存失效,进而其它线程会从内存读取这个变量,此机制来实现对其它线程的可见性。但是此关键字不是原子性的,因此并不能保证线程安全。
接近 2 年之前 回复
learningcsdn
learningcsdn 嗯嗯,感谢回答,今天又学习了下,总结来说就是volatile关键字会把一个线程对其的修改立刻回写到内存,并使其它线程的缓存失效,进而其它线程会从内存读取这个变量,此机制来实现对其它线程的可见性。但是此关键字不是原子性的,因此并不能保证线程安全。
接近 2 年之前 回复
learningcsdn
learningcsdn 嗯嗯,感谢回答,今天又学习了下,总结来说就是volatile关键字会把一个线程对其的修改立刻回写到内存,并使其它线程的缓存失效,进而其它线程会从内存读取这个变量,此机制来实现对其它线程的可见性。但是此关键字不是原子性的,因此并不能保证线程安全。
接近 2 年之前 回复
learningcsdn
learningcsdn 嗯嗯,感谢回答,今天又学习了下,总结来说就是volatile关键字会把一个线程对其的修改立刻回写到内存,并使其它线程的缓存失效,进而其它线程会从内存读取这个变量,此机制来实现对其它线程的可见性。但是此关键字不是原子性的,因此并不能保证线程安全。
接近 2 年之前 回复
learningcsdn
learningcsdn 嗯嗯,感谢回答,今天又学习了下,总结来说就是volatile关键字会把一个线程对其的修改立刻回写到内存,并使其它线程的缓存失效,进而其它线程会从内存读取这个变量,此机制来实现对其它线程的可见性。但是此关键字不是原子性的,因此并不能保证线程安全。
接近 2 年之前 回复
learningcsdn
learningcsdn 嗯嗯,感谢回答,今天又学习了下,总结来说就是volatile关键字会把一个线程对其的修改立刻回写到内存,并使其它线程的缓存失效,进而其它线程会从内存读取这个变量,此机制来实现对其它线程的可见性。但是此关键字不是原子性的,因此并不能保证线程安全。
接近 2 年之前 回复
wojiushiwo945you
wojiushiwo945you   Ds   Rxr 2016.03.01 10:17

指令重排:是指我们的代码的执行顺序可能跟它们的编写顺序不一致,因为java编译器在编译过程中会进行代码优化,而提前执行某些语句。
使用这个关键字就可以禁止编译器对该变量的操作代码进行重排优化,保证代码的执行顺序。而普通变量就不能保证了。

learningcsdn
learningcsdn 嗯嗯,明白了,多谢多谢
接近 2 年之前 回复
Csdn user default icon
上传中...
上传图片
插入图片
准确详细的回答,更有利于被提问者采纳,从而获得C币。复制、灌水、广告等回答会被删除,是时候展现真正的技术了!