volatile

volatile的原理

volatile是轻量级的synchronized。保证"可见性",线程每次都会去主内存去读变量,而不是缓存;保证有序性,即不会出现指令重排。但volatile无法保证复合操作的原子性,对任意单个volatile变量的读/写(单纯赋值)具有原子性,但类似于volatile++、flag = !flag这种复合操作是不具有原子性。所以不能代替synchronized!底层用内存屏障实现。

内存屏障:内存屏障是一组处理器指令,它的作用是禁止指令重排序和解决内存可见性的问题。使用 volatile 修饰变量时,根据 volatile 重排序规则表,Java 编译器在生成字节码时,会在指令序列中插入内存屏障指令来禁止特定类型的处理器重排序。JVM中的内存屏障指令有四种:LoadLoad、StoreStore、LoadStore、StoreLoad。Load是读取、Store是写入,所谓的LoadStore就是确保所有Load1读取在所有Store2写之前。

happen-before八大原则

JVM可以通过happens-before关系向程序员提供跨线程的内存可见性保证(如果A线程的写操作a与B线程的读操作b之间存在happens-before关系,尽管a操作和b操作在不同的线程中执行,但JMM向程序员保证a操作将对b操作可见)。

  • 单线程happen-before原则:在同一个线程中,书写在前面的操作happen-before后面的操作。
  • 锁的happen-before原则:同一个锁的unlock操作happen-before此锁的lock操作。
  • volatile的happen-before原则:对一个volatile变量的写操作happen-before对此变量的任意操作(当然也包括写操作了)。
  • happen-before的传递性原则:如果A操作 happen-before B操作,B操作happen-before C操作,那么A操作happen-before C操作。
  • 线程启动的happen-before原则:同一个线程的start方法happen-before此线程的其它方法。
  • 线程中断的happen-before原则:对线程interrupt方法的调用happen-before被中断线程的检测到中断发送的代码。
  • 线程终结的happen-before原则:线程中的所有操作都happen-before线程的终止检测。
  • 对象创建的happen-before原则:一个对象的初始化完成先于他的finalize方法调用。

DCL失效怎么解决, 设计模式

    public static SingletonLazyDCL getInstance() {
        /*
         DCL(double check lock)是加锁懒汉的改进版,直接在方法上加锁会影响性能,因为初始化好了后,这个方法还要加锁就开销大、不合理了
         所以方法不加锁,而是在方法内双重判断
         */
        if (instance == null) { // 初始化的时候可能有多个线程第一道防线检测通过
            synchronized (SingletonLazyDCL.class) {  // 没有初始化才进行加锁!
                if (instance == null) {
                    /*
                     第二道防线为什么有?这里其中一个线程拿到锁,进来判断为空,进行初始化,完毕后,其他通过第一道防线的线程拿到锁
                     进来判断为空则直接返回,所以即保证了线程安全,也保证了单例的高效性能。
                     如果volatile关键则省略了,那么此处可能读取的是CPU缓存内的instance,或者因为jvm指令重排,就算第一个线程
                     实例化成功了,第二个拿到锁进来判断时候可能:
                        1、还有可能是空,又进行实例化!(读取的是CPU缓存内的instance)
                        2、new单例时分3步走(1内存开辟空间;2进行较耗时的初始化;3instance引用指向空间)
                        第一个线程可能动作比较快,又出现了指令重排,第2步还没走他先第3步将instance指向空间了,就是不为空了,其他
                        线程判断发现instance不为空,直接返回,但其实instance还没初始化好,此时用instance就出现异常了。
                     这就是著名的"DCL失效"问题。
                     */
                    instance = new SingletonLazyDCL();
                }
            }
        }
        return instance;
    }
posted @ 2021-04-22 10:41  i%2  阅读(44)  评论(0)    收藏  举报