当前位置: 首页 > 后端技术 > Java

Volatile关键字分析

时间:2023-04-01 16:57:15 Java

Volatile关键字分析1:禁止指令重排Volatile公共类Singleton的识别{publicstaticvolatileSingletonsingleton;publicstaticSingletongetSingleton(){if(singleton==null){synchronized(Singleton.class){if(singleton==null){singleton=newSingleton();}}}返回单例;为什么在单例中使用volatile?编译器和处理器的目标是在不改变程序执行结果的情况下,尽可能提高执行效率。一些指令将被重新排序。在创建对象(newSingleton())的过程中,可以分为4个步骤:1:加载类对象2:分配内存空间3:调用构造函数,初始化实例4:重排序时返回引用地址可能会出现对象未初始化返回引用地址时,其他线程判断对象不为空,直接使用,但对象还是半成品,可能会导致空指针异常.所以在创建单例的时候使用volatile就是为了禁止指令重排。2:内存可见性JMM:1:每个线程也有自己的工作内存,线程的工作内存保留了线程使用的变量的工作副本。2:线程对变量的所有操作(读、取)都必须在工作内存中进行,不能直接在主内存中读写变量。3:不同线程不能直接访问彼此工作内存中的变量,线程间变量值的传递需要通过主存传递来完成。本地内存和主内存的关系:volatile变量在读取时总能拿到其他线程最后写入的值。写入:当写入一个volatile变量时,线程工作内存中的变量值被刷新到主内存中。读取:读取volatile变量时,先将工作内存中的变量设置为无效,再从主内存中获取最新的有效值。volatile是通过MESI(缓存一致性协议)+嗅探实现的。嗅探可以知道其他内存中的volatile修饰变量在其他线程中是否过期,过期后直接从主存中读取数据。三:Volatile使用场景一:Volatile只能保证可见性和有序性,不能保证原子性。在多线程的情况下,Volatile变量不要做非原子操作如:"i++",可以做:"i=true"2:使用Volatile时要小心,Volatile使用嗅探可见性,如果变量太多了会导致“公交风暴”;4:总结1:volatile修饰符适用于以下场景:一个属性被多个线程共享,一个线程修改这个属性,其他线程可以立即得到修改后的值。比如布尔标志;或者作为触发器来实现轻量级的同步。2:volatile属性的读写操作是无锁的,不能替代synchronized,因为它不提供原子性和互斥性。因为没有锁,所以不需要花时间在获取和释放锁上,所以说成本低。3:volatile只能作用于属性。我们使用volatile来修改属性,这样编译器就不会对该属性的指令重新排序。4:volatile提供可见性,一个线程的任何修改都会立即被其他线程看到,volatile属性不会被线程缓存,总是从主存中读取。5:volatile提供了happens-before保证,对volatile变量v的写入happens-before其他线程对v的所有后续读取操作。6:volatile可以实现可见性,禁止单例双校验中的指令重排序,从而保证安全性。