volatile
轻量级同步机制。
volatile保证了可见性,不保证原子性,保证了有序性(禁止指令重排)。
*可见性:java全局变量存在主内存,线程运行时把变量值拷贝到自己的工作内存在操作,操作完成在写回主内存。线程之间的工作内存互相是不可见的,volatile关键字修饰的变量,保证了可见性,即某线程修改了主内存值,其他线程可以及时拿到最新值。
*不保证原子性:原子性是指数据的完整一致性,不可分割,操作数据要么同时成功要么同时失败!多线程操作数值加加操作时,不加锁volatile修饰不能保证原子性。
解决方法(1)加synchronized加锁。但是效率低(2)使用原子类AtomicInteger
*禁止指令重排:jvm虚拟机对于没有依赖性的代码,会进行优化重排。比如instance = new SingletonDemo()经过汇编会变成三句,其中没有依赖关系的语句就有可能会发生重排。
单线程情况下没有数据安全问题,多线程情况下可能会发生数据安全问题。
Volatile使用场景:多线程情况下的单例模式
代码示例:
public class SingletonDemo { private static volatile SingletonDemo instance = null;//添加volatile关键字,禁止指令重拍 private SingletonDemo(){ System.out.println("实例初始化...."); } public static SingletonDemo getinstance(){ //DCL双端检索 if(instance == null){ synchronized(SingletonDemo.class){ if(instance == null){ instance = new SingletonDemo(); } } } return instance; } public static void main(String[] args){ /*new Thread(() -> { System.out.print("1"); },1).start();*/ for(int i = 0 ;i<1000;i++){ ThreadDemo td = new ThreadDemo(); new Thread(td).start(); } } }
public class ThreadDemo implements Runnable{ private boolean flag = false; public void run(){ /*try{ // 该线程 sleep(200), 导致了程序无法执行成功 Thread.sleep(200); }catch(InterruptedException e){ e.printStackTrace(); } flag = true; System.out.println("flag="+isFlag());*/ SingletonDemo.getinstance(); } public boolean isFlag(){ return flag; } public void setFlag(boolean flag){ this.flag = flag; } }