volatile关键字的特性
- 保证代码执行的有序性
- 内存屏障
- 可见性
- MESI
- 缓存一致性协议
- 但是volatile不能保证程序的原子性
在下面这个例子里,count++表示了取值,计算和存储三个步骤,指的是不能保证这三个步骤的原子性,虽然count值可见,但是整个计算过程volatile不能保证。
package juc.volatil;
import java.util.ArrayList;
import java.util.List;
//volatile的不能保证原子性
public class T2 {
private /*volatile*/ int count = 0;
public synchronized void m() {
for (int i = 0; i < 10000;i++) count++;
}
public static void main(String[] args) {
List<Thread> threads = new ArrayList<Thread>();
T2 t = new T2();
for (int i = 0; i< 10;i++)
{
threads.add(new Thread(()-> {t.m();}));
}
threads.forEach((o)->{o.start();});
threads.forEach((o)->{try {
o.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}});
System.out.println(t.count);
}
}
volatile的底层实现
- 可见性-缓存一致性(TBD)
- 防止重排序-内存屏障(JMM TBD)
一个有名的singleton的线程安全实现
package juc.volatil;
public class T1 {
private volatile static T1 INSTANCE;
public static T1 getInstance() {
if(INSTANCE == null)
{
try {
Thread.sleep(300);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized(T1.class) {
INSTANCE = new T1();
}
}
return INSTANCE;
}
public static void main(String[] args) {
for(int i = 0 ;i < 100 ;i++)
{ new Thread(()->{
System.out.println(T1.getInstance().hashCode());
}).start();
}
}
}