一、volatile的使用
1、防止重排序
- 在并发环境下实现单例模式,我们通常可以采用双重检查加锁(DCL)的方式来现实:
public class Singleton { public static volatile Singleton singleton; private Singleton() {} public static Singleton getInstance() { if(singleton == null) { synchronized (singleton) { if(singleton == null) { singleton = new Singleton(); } } } return singleton; } }
实例化一个对象其实可以分为三个步骤:
(1)分配内存空间
(2)初始化对象
(3)将内存空间的地址赋值给对应的引用。
但是由于操作系统可以对指令进行重排序,所以上面的过程也可能变成如下过程:
(1)分配内存空间
(2)将内存空间的地址赋值给对应的引用。
(3)初始化对象
如果这是个流程,多线程环境下就可能将一个未初始化的对象引用暴露出来,从而导致不可预料的结果。因此,为了防止这个过程的重排序,我们需要将变量设置为volatile类型的变量。
2、实现可见性
- 可见性问题主要指一个线程修改了共享变量值,而另一个线程却看不到。引起可见性问题的主要原因就是每个线程拥有自己的高速缓存区——线程工作内存。volatile关键字能有效解决这个问题。
public class VolatileTest { int a = 1; int b = 2; public void change() { a = 3; b = a; } public void print() { System.out.println("b=" + b + ";a=" + a); } public static void main() { final VolatileTest bean = new VolatileTest(); new Thread(new Runnable() { public void run() { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } bean.change(); } }).start(); new Thread(new Runnable() { public void run() { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } bean.print(); } }).start(); } public static void main(String[] args) { for(int i = 0; i < 10; i++) { main(); } } }
直观上说,这段代码的结果只可能有两种:b=3;a=3或者b=2;a=1。不过运行上面的代码,却出现了三种情况:
原文地址:https://www.cnblogs.com/lynn16/p/10705895.html
时间: 2024-11-14 12:30:33