多线程进阶JUC之Volatile三大特性和的单例模式

Volatile三大特性

保证可见性

/**
 * volatile可见性
 * @Author Weton Li
 * @Date 2021/2/11 22:11
 */
public class JMMdemo1 {
    
    
    // 若不使用volatile,程序会死循环
    private volatile static int num = 0; // 保证volatile可见性
    public static void main(String[] args) {
    
    
        new Thread(()->{
    
     // 线程1对主内存的变化不知晓,需给num加volatile,显示可见性
            while (num == 0) {
    
    

            }
        }).start();

        try {
    
    
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }

        num =1;
        System.out.println(num);
    }
}

不保证原子性

在这里插入图片描述

/**
 * volatile不保证原子性,在方法中加锁
 * 若不用锁,如何保证原子性
 * @Author Weton Li
 * @Date 2021/2/12 09:55
 */
public class JMMdemo2 {
    
    

//    private volatile static int num = 0;
    private  static AtomicInteger num = new AtomicInteger(); // 原子包装类,底层使用CAS

    public /*synchronized*/ static void add(){
    
    
//        num++;
        num.incrementAndGet(); // 在内存中修改值,而不是num++。类的底层直接和操作系统挂钩,Unsafe类是特殊的存在
    }

    public static void main(String[] args) {
    
    
        for (int i = 1; i <= 20; i++) {
    
    
            new Thread(()->{
    
    
                for (int j = 0; j < 1000; j++) {
    
    
                    add();
                }
            }).start();

        }

        while (Thread.activeCount() > 2) {
    
    
            Thread.yield();
        }
        System.out.println(Thread.currentThread().getName()+"->"+num);
    }
}

禁止指令重排

在逻辑问题上产生,但在实际运行中基本不会发生
在这里插入图片描述
内存屏障,CPU指令。作用:保证特定的操作的执行顺序。保证某些变量的内存可见性。
在这里插入图片描述

单例模式

/**
 * 懒汉式
 *
 * @Author Weton Li
 * @Date 2021/2/12 11:07
 */
public class Lazy {
    
    

    // 红绿灯
    private static boolean qinjiang = false;
    private Lazy(){
    
    
        synchronized (Lazy.class){
    
    
            if (qinjiang == false){
    
    
                qinjiang = true;
            }else {
    
    
//                if (lazy != null) {
    
    
                    throw new RuntimeException("不要试图使用反射破坏异常");
//                }
            }

        }
        System.out.println(Thread.currentThread().getName()+"->ok");
    }

    private volatile static Lazy lazy;

    /**
     * 双重检测锁模式,DCL懒汉式,加原子性操作,使用volatile防止指令重排现象发生
     * @return
     */
    public /*synchronized*/ static Lazy getInstance(){
    
    
        if (lazy == null) {
    
    
            synchronized (Lazy.class){
    
    
                if (lazy == null) {
    
    
                    lazy = new Lazy(); // 不是原子性操作
                    /**
                     * 1.分配内存空间
                     * 2.执行构造方法,初始化对象
                     * 3.把对象指向这个空间
                     * 如果发生指令重排132,A线程没问题,B认为lazy!=null完蛋。
                     */
                }
            }
        }

        return lazy;
    }

    public static void main(String[] args) throws Exception {
    
    

        Field qinjiang = Lazy.class.getDeclaredField("qinjiang");
        qinjiang.setAccessible(true);
//        for (int i = 1; i <= 10 ; i++) {
    
    
//            new Thread(()->{
    
    
//                Lazy.getInstance();
//            }).start();
//        }
//        Lazy lazy1 = Lazy.getInstance();
        Constructor<Lazy> declaredConstructor = Lazy.class.getDeclaredConstructor(null);
        declaredConstructor.setAccessible(true); // 无视私有构造器
        Lazy lazy1 = declaredConstructor.newInstance();

        qinjiang.set(lazy1,false); // 道高一尺魔高一丈,又被改回来了

        Lazy lazy2 = declaredConstructor.newInstance();
        System.out.println(lazy1+"/"+lazy2); // 不同
    }
}

猜你喜欢

转载自blog.csdn.net/m0_47119598/article/details/113793739