volatile是java虚拟机提供的轻量级的同步机制。
一,voltaile的特性:保证可见性,不保证原子性,禁止指令重排
1.验证volatile的可见性代码:
class MyData{ volatile int num = 0; void incrementNum(){ this.num = num + 60; } } public class VolatileMain { public static void main(String[] args) { MyData myData = new MyData(); new Thread(()->{ try { TimeUnit.SECONDS.sleep(6); } catch (InterruptedException e) { e.printStackTrace(); } myData.incrementNum(); System.out.println(Thread.currentThread().getName()+"--->"+myData.num); },"AAA").start(); while (myData.num == 0){ } System.out.println(Thread.currentThread().getName()+"t"+myData.num); } }
2.验证volatile不保证原子性代码:
class MyData1{ volatile int num = 0; void incrementNum(){ this.num = num + 60; } void addPlus(){ this.num++; } } public class VolatileAtomicValid { public static void main(String[] args) { MyData1 myData1 = new MyData1(); for (int i = 0; i < 20; i++) { new Thread(()->{ for (int j = 1; j <= 1000; j++) { myData1.addPlus(); } },String.valueOf(i)).start(); } while (Thread.activeCount() > 2){ Thread.yield(); } System.out.println(Thread.currentThread().getName() + "t" + "finally number value:" + myData1.num); } } console 输出:main finally number value:14885
3.volatile禁止指定重排:
class ReSortDemo{ volatile int a = 0; volatile boolean flag = false; public void method01(){ a = 1; flag = true; } // 多线程环境中线程交替执行,由于编译器优化重排的存在, //两个线程中使用的变量能否保证一致时无法确定的,结果无法预测 public void method02(){ if(flag){ a = a + 5; System.out.println("******retValue" + a); } } }
二,单例模式下在多线程环境下可能存在安全问题
1. 单线程情况下
public class SingletonDemo { private static SingletonDemo singletonDemo = null; public SingletonDemo() { System.out.println(Thread.currentThread().getName() + "t 构造方法SingletonDemo"); } public static SingletonDemo getInstance(){ if(singletonDemo == null){ singletonDemo = new SingletonDemo(); } return singletonDemo; } public static void main(String[] args) { System.out.println(SingletonDemo.getInstance() == SingletonDemo.getInstance()); System.out.println(SingletonDemo.getInstance() == SingletonDemo.getInstance()); System.out.println(SingletonDemo.getInstance() == SingletonDemo.getInstance()); } } console输出 main 构造方法SingletonDemo true true true
2. 多线程情况下
public class SingletonDemo { private static SingletonDemo singletonDemo = null; public SingletonDemo() { System.out.println(Thread.currentThread().getName() + "t 构造方法SingletonDemo"); } public static SingletonDemo getInstance(){ if(singletonDemo == null){ singletonDemo = new SingletonDemo(); } return singletonDemo; } public static void main(String[] args) { for (int i = 0; i < 10; i++) { new Thread(()->{ SingletonDemo.getInstance(); },String.valueOf(i)).start(); } } } console输出: 0 构造方法SingletonDemo 7 构造方法SingletonDemo 3 构造方法SingletonDemo 5 构造方法SingletonDemo 1 构造方法SingletonDemo
3.解决办法:
(1)加synchronized
public static synchronized SingletonDemo getInstance(){ if(singletonDemo == null){ singletonDemo = new SingletonDemo(); } return singletonDemo; } console输出: 0 构造方法SingletonDemo 缺点:在单例模式下加synchronized 能够保证数据的一致性,但并发性下降
(2)DCL模式(double check lock)
public static synchronized SingletonDemo getInstance(){ if(singletonDemo == null){ synchronized (SingletonDemo.class){ if(singletonDemo == null){ singletonDemo = new SingletonDemo(); } } } return singletonDemo; } console输出: 0 构造方法SingletonDemo 缺点:(双端检锁)机制不一定线程安全,原因时有指令重排的存在,加入volatile可以禁止指令重排
(3) 缺点:(双端检锁)机制不一定线程安全,原因时有指令重排的存在,加入volatile可以禁止
指令重排。
private static volatile SingletonDemo singletonDemo = null;
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)