Volatile和Synchronized有什么区别?Volatile能不能保证线程安全?DCL(Double Check Lock)单例为什么要加Volatile?:
Synchronized关键字,用来加锁.Volatile只是保持变量的线程可见性.通常适用于一个线程写,多个线程读的场景.
Volatile关键字只能保证线程可见性,不能保证原子性.
/**
* 如果变量flag没有加volatile关键字,则线程无法读取到
* 主线程将变量flag修改为false(可见性)
*/
private static volatile boolean flag = true;
public static void main(String[] args) {
new Thread(()->{
while (flag){
}
System.out.println("==========End of Thread01===========");
}).start();
System.out.println("true flag off");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
flag=false;
}
原因分析:
如上图所示,所有线程的共享变量都存储在主内存中,每一个线程都有一个独有的工作内存,每个线程不直接操作在主内存中的变量,而是将主内存上变量的副本放进自己的工作内存中,只操作工作内存中的数据.当修改完毕后,再把修改后的结构放回到主内存中.每个线程都只操作自己工作内存中的变量,无法直接访问对方工作内存中的变量,线程间变量值的传递需要通过主内存来完成.
此时如果对变量加上volatile关键字修饰的话,它可以保证当A线程对共享变量的值做了变动之后,会立即刷回到主内存中,而其他线程读取到该变量的值也会作废,强迫重新从主内存中读取该变量的值,这样在任何时刻,AB线程总是会看到变量I的同一个值.
解决方案:
DCL(Double Check Lock)单例为什么要加Volatile?
Volatile另一作用,防止指令重排
private static SingleDemo1 singleDemo1;
private SingleDemo1(){}
public SingleDemo1 getInstance(){
//双重检测,对象创建重复
if (null == singleDemo1){
synchronized (SingleDemo1.class){
if (null == singleDemo1){
singleDemo1 = new SingleDemo1();
}
}
}
return singleDemo1;
}