一、话不多说

  • 先自行简单了解下 Java 内存模型中的可见性、原子性和有序性。
package com.wx;

/**
 * @program: teddylife
 * @description: 单例模式DCL双重检查
 * @author: Mr.Teddy
 * @create: 2020-09-15 14:18
 **/
public class Test {
    private static volatile Test INSTANCE;

    private Test () {}

    public static Test getInstance() {

        if (INSTANCE == null) { // Double Check Lock
            // 开启双层检查
            synchronized (Test.class) {
                if (INSTANCE == null) {
                    try {
                        Thread.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    INSTANCE = new Test();
                }
            }
        }
        return INSTANCE;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(() -> System.out.println(Test.getInstance().hashCode())).start();
        }
    }
}

二、注释

  • volatile 关键字 (1.线程可见性 2.禁止指令重排序)
  • 1线程可见性 (可见性)

可见性,是指线程之间的可见性,一个线程修改的状态对另一个线程是可见的。也就是一个线程修改的结果。另一个线程马上就能看到。比如:用volatile修饰的变量,就会具有可见性。volatile修饰的变量不允许线程内部缓存和重排序,即直接修改内存。所以对其他线程是可见的。但是这里需要注意一个问题,volatile只能让被他修饰内容具有可见性,但不能保证它具有原子性。比如 volatile int a = 0;之后有一个操作 a++;这个变量a具有可见性,但是a++ 依然是一个非原子操作,也就是这个操作同样存在线程安全问题。
在 Java 中 volatile、synchronized 和 final 实现可见性。

  • 2禁止指令重排序 (有序性)

Java 语言提供了 volatile 和 synchronized 两个关键字来保证线程之间操作的有序性,volatile 是因为其本身包含“禁止指令重排序”的语义,synchronized 是由“一个变量在同一个时刻只允许一条线程对其进行 lock 操作”这条规则获得的,此规则决定了持有同一个对象锁的两个同步块只能串行执行。

  • volatile 性能

volatile 的读性能消耗与普通变量几乎相同,但是写操作稍慢,因为它需要在本地代码中插入许多内存屏障指令来保证处理器不发生乱序执行。

😁 作者:Teddy