volatile关键字理解

volatile是一个轻量级的同步机制,相比传统的锁(如synchronized),在性能上面是有优势的,但是虚拟机对锁有过优化,所以很难确切的说volatile比synchronize快上多少。

volatile三大特性

  1. 保证可见性
  2. 防止指令重排
  3. 不保证原子性

一、保证可见性

  Java内存模型(JMM)规定了所有的变量都存储在主内存中,每个线程都在自己的工作内存中维护着变量的副本,对变量的所有操作都是在工作内存中进行的,不同的线程之间无法访问对方工作内存中的变量,线程之间变量值的传递都需要通过主内存来完成。

  当一个变量被定义为volatile后,一个线程修改了变量值后,其他线程会立即得知(原理:当主内存中的变量被修改后,会通知其他线程将自己工作内存中的该变量副本设置为无效,如果在使用到这个变量时,发现是无效状态,就会从主内存中重新读取),所以这就是所谓的“可见性”。

二、防止指令重排

  Java中会存在指令重排优化,这是我们无法感知到的,但是在多线程情况下,指令重排可能会导致问题或者资源浪费,所以使用volatile关键字可以防止指令重排,举一个简单的单例实现:

 1     // 定义volatile变量,防止指令重排,对象实例化的过程并不是原子性的,所以存在Java编译器指令重排优化可能
 2     // 对象实例化过程:1.分配内存空间 2.初始化对象 3.将对象的引用指向分配的内存
 3     // 如果不加volatile,因为存在指令重排的可能,就可能存在其他线程拿到未初始化完成的对象,从而导致线程不安全
 4     private volatile static Singleton instance;
 5 
 6     public Singleton getInstance() {
 7         // 多线程情况下,防止重复实例化,浪费资源和效率
 8         if (instance == null) {
 9             // 加锁进行控制,防止多线程情况下重复实例化
10             synchronized (Singleton.class) {
11                 // 多线程情况下,获取到锁后也再判断一下,如果其他线程已经实例化,也就无需再次实例化,还是防止重复实例化
12                 if (instance == null) {
13                     instance = new Singleton();
14                 }
15             }
16         }
17         return instance;
18     }

三、不保证原子性

   对于非原子性操作,如i++,会存在问题,可以使用atomic包下的相关类来保证原子性

  

posted @ 2022-04-27 18:08  什么时候GC  阅读(44)  评论(0)    收藏  举报