Java多线程——(Volatile)

Volatile简介

在上一节中,[Java多线程——用之初体验](https://www.jianshu.com/p/4944cd118e31)中,  
对使用以及对Java内存模型有所了解。关于Volatile简单的说就是JMM提供能够保证一个线程更新  
值后,其他线程能够及时读取的机制。并且该关键词的修饰下前后的代码不会被java虚拟机重排序

一般使用场景

  • 可见性的使用
    循环的结束标志
        public class VolatileLogic {
            private   boolean isStop = false;
        
            /**
             * 模拟循环处理的逻辑
             */
            public void loopDealProcess() {
                while (!isStop) {
        //            try {
        //                Thread.sleep(10);
        //            } catch (InterruptedException e) {
        //                e.printStackTrace();
        //            }
                }
            }
        
            public void setStop(boolean stop) {
                isStop = stop;
            }
        
        }
    main函数测试类
    class VolatileDemo {
    
    public static void main(String[] args) {
        VolatileLogic volatileLogic = new VolatileLogic();
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
                volatileLogic.loopDealProcess();
                System.out.println(Thread.currentThread().getName()+"结束");
            }
        });
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                volatileLogic.setStop(true);
                System.out.println(Thread.currentThread().getName()+"结束");
            }
        });
        thread.start();
        thread.setName("loopDealProcess");
        thread1.start();
        thread1.setName("setStop");
    }
    
    

}
```

我这截取了该程序运行的结果如下
```
不加volatile结果如下:
loopDealProcess
setStop
setStop结束
该程序没有正常结束,一直卡在loopDealProcess的死循环中,需要手动停止  
加volatile结果如下:
loopDealProcess
setStop
setStop结束
loopDealProcess结束
该程序能够在setStop后立刻通知到loopDealProcess该值的状态
```  

一般可见性的运用是一个线程对单独的变量进行读写操作,其他线程对变量只有读操作。JMM能及时的将一个线程的写操作同步到其他的线程内存中去。

  • 有序性
    由于cpu在执行代码逻辑的时候会对无关结果的指令进行重排序——>指令优化
    public class Singleton {
    
    private static volatile Singleton instance;
    
    private Singleton(){}
    // DCL
    public static Singleton getInstance(){
        if(instance ==null){   //第一次检查
            synchronized (Singleton.class){
                if(instance == null){   //第二次检查
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
    

}

因为又指令重排序的存在,双重锁的机制也不能保证安全。  
因为new Singleton()这个分为三个步骤  
1. 给 instance 分配内存
2.调用 instance 的构造函数来初始化对象
3.将 instance 对象指向分配的内存空间(执行完这步 instance 就为非 null 了)  

步骤 2 和 3 不存在数据依赖关系,如果虚拟机存在指令重排序优化,则步骤 2和 3 的顺序是无法确定的。如果A线程率先进入同步代码块并先执行了 3 而没有执行 2,此时因为 instance 已经非 null。这时候线程 B 在第一次检查的时候,会发现 instance 已经是 非null 了,就将其返回使用,但是此时 instance 实际上还未初始化,自然就会出错。所以我们要限制实例对象的指令重排,用 volatile 修饰(JDK 5 之前使用了 volatile 的双检锁是有问题的)。

总结:Volatile可以保证同步操作中的,可见性和有序性。对需要涉及到原子性的操作时无法保证的。

你可能感兴趣的:(Java多线程——(Volatile))