美文网首页
volatile关键字

volatile关键字

作者: 永远的太阳0123 | 来源:发表于2018-09-17 20:42 被阅读0次
1 volatile的可见性

在本地内存中,每次使用volatile型变量都必须从主内存中获取数值,这可以保证获取的是其它线程对这个volatile型变量所做的修改后的数值;每次修改volatile型变量都必须立刻同步到主内存中,这可以保证其它线程获取的是当前线程对这个volatile型变量所做的修改后的数值。

2 volatile禁止指令重排序

volatile修饰的变量不会被指令重排序优化,保证代码的执行顺序与程序的顺序相同。
volatile的禁止重排序并不局限于两个 volatile 的属性操作不能重排序,而且是 volatile 属性操作和它周围的普通属性的操作也不能重排序。
之前 instance = new Singleton() 中,如果 instance 是 volatile 的,那么对于 instance 的赋值操作(赋一个引用给 instance 变量)就不会和构造函数中的属性赋值发生重排序,能保证构造方法结束后,才将此对象引用赋值给 instance。

根据 volatile 的内存可见性和禁止重排序,那么我们不难得出一个推论:线程 a 如果写入一个 volatile 变量,此时线程 b 再读取这个变量,那么此时对于线程 a 可见的所有属性对于线程 b 都是可见的。

3 volatile的使用场景

volatile 修饰符适用于以下场景:某个属性被多个线程共享,其中有一个线程修改了此属性,其他线程可以立即得到修改后的值。在并发包的源码中,它使用得非常多。

示例三:volatile保证可见性,而synchronized保证原子性。

public class Test6 {

    volatile int count = 0;

    public synchronized void m() {
        for (int i = 0; i < 10000; i++) {
            count++;
        }
    }

    public static void main(String[] args) {
        Test6 t = new Test6();
        List<Thread> threads = new ArrayList<>();
        // 创建10个线程
        for (int i = 0; i < 10; i++) {
            threads.add(new Thread(new Runnable() {
                public void run() {
                    t.m();
                }
            }));
        }
        // 启动线程
        for (Thread thread : threads) {
            thread.start();
        }
        // 确保10个线程执行完毕后,再执行主线程的输出
        for (Thread thread : threads) {
            try {
                thread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(t.count);// 输出100000
    }
}

相关文章

网友评论

      本文标题:volatile关键字

      本文链接:https://www.haomeiwen.com/subject/jkpdnftx.html