美文网首页
5.volatile:有序性

5.volatile:有序性

作者: xialedoucaicai | 来源:发表于2018-06-13 16:07 被阅读0次

1.什么是有序性

程序按照写代码的先后顺序执行,就是有序的。程序难道还能不按代码顺序执行?这就涉及到CPU的指令重排序问题。

2.指令重排

处理器为了提高程序运行效率,可能会对输入代码进行优化,它不保证程序中各个语句的执行先后顺序同代码中的顺序一致,但是它会保证程序最终执行结果和代码顺序执行的结果是一致的。那它如何保证即使重排最终结果也能正确呢?
答案就是保证指令数据间依赖关系不会被重排所影响。看如下例子:

int a = 10;    //语句1
int r = 2;    //语句2
a = a + 3;    //语句3
r = a*a;     //语句4

语句2 3 4之间存在相互依赖关系,所以重排的结果一定会保证2->3->4这个顺序,但是1 2顺序就不一定了。
这种重排在单线程中没有问题,但对于对线程就可能存在问题了,看如下代码:

//线程1:
context = loadContext();   //语句1
inited = true;             //语句2
 
 //线程2:
while(!inited ){
   sleep()
}
doSomethingwithconfig(context);

线程1中语句1 2之间没有依赖,可能会先执行inited=true;这将导致线程2收到错误的消息,使用还未初始化的context。不过我代码是怎么都不能重现,它总是按代码顺序执行,这就没法验证了。
我们可以为inited加上volatile关键字,这样在对inited修改前,一定会保证之前的代码全部执行完了,就不会出现重排导致的问题了。
关于指令重排还有很多内容,比如happens-before原则,内存屏障等等,要完全理解可能要深入到硬件,比较复杂和专业,再深入下去感觉要走火入魔,怕钻进去出不来,所以浅尝辄止了,大家有兴趣可以继续深入了解。

3.最佳实践

volatile禁止指令重排,最典型的应用应该就是双重锁的单例模式了。看代码

public class SecondSingleton {
    //volatile关键字保证可见性 同时禁用指令重排(jdk1.5后生效)
    private static volatile SecondSingleton singleton;
    
    private SecondSingleton(){
        
    }
    
    /**
     * 双重检查锁实现单例模式
     * 推荐这样写,既保证线程安全,又延迟加载
     * @return
     */
    public static SecondSingleton getSingleton() {
        if (singleton == null) {
            synchronized (SecondSingleton.class) {
                if(singleton == null){
                    singleton = new SecondSingleton();
                }
            }
        }
        return singleton;
    }
}

为什么要使用volatile修饰singleton?
主要在于singleton = new SecondSingleton();这句,这并非是一个原子操作,事实上在 JVM 中这句话大概做了下面 3 件事情:

  1. 给 singleton 分配内存
  2. 调用 SecondSingleton的构造函数来初始化成员变量
  3. 将singleton 对象指向分配的内存空间(执行完这步 singleton 就为非 null 了)

但是由于指令重排,上述第二步和第三步的顺序是不能保证的,最终的执行顺序可能是 1->2->3 也可能是 1->3->2。如果是后者,则在 3 执行完毕,2 未执行之前,另一个线程执行if (singleton == null) ,这时 singleton 已经是非 null 了,但却没有初始化,所以该线程会直接返回 singleton ,然后使用,自然就会报错了。

相关文章

  • 5.volatile:有序性

    1.什么是有序性 程序按照写代码的先后顺序执行,就是有序的。程序难道还能不按代码顺序执行?这就涉及到CPU的指令重...

  • 5.volatile:初识

    前言 我是学完了也没理解到这个易变的/不稳定的是怎么体现的,怪不得总是说volatile关键字,而不会说"易变的"...

  • Java多线程之有序性(二)

    好了,上一章我们讲了有序性出现问题的原因,今天我们来细讲一下有序性的保证方式。书上有一段比较匪夷所思的关于有序性定...

  • 2详解Happens-Before原则(解决并发编程可见性、有序

    并发的三个特性:原子性,可见性,有序性 可见性 -> 缓存有序性 -> 编译优化 volatile 使用 介绍 v...

  • 吃透Java并发:volatile是怎么保证可见性的

    前言 volatile关键字能够保证可见性和有序性,但是volatile为什么能够保证可见性和有序性?为什么vol...

  • Kafka 调研

    1. 基本概念 2. 重要配置 2.1 有序性保证 对于有序性要求严格的场景,将 retries 时间设置为 Br...

  • Kafka特性

    一、消息有序性 consumer的offset实现分区级别的有序性。broker在消息持久化的时候是追加写入分区文...

  • 《实战高并发程序设计》读书笔记-线程基本知识补充

    volatile   Java内存模型都是围绕着原子性、有序性和可见性展开的,为了在适当的场合,确保线程间的有序性...

  • Volatile关键字从理解到实操,源码实例深度剖析

    谈到并发编程 ,必知晓并发三要素 :原子性、可见性、有序性。而 Volatile 涉及了可见性与有序性,是轻量级的...

  • jvm

    JAVA内存模型: 有序性、可见性、原子性 导致可见性的原因是缓存,导致有序性的原因是编译优化 涉及 vol...

网友评论

      本文标题:5.volatile:有序性

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