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;