原博文地址:http://www.cnblogs.com/dolphin0520/p/3920373.html
这里只是对上面的博文的一个简单总结,总结如下:
volatile变量保证可见性实现
volatile变量保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。如何实现:
1. volatile变量规则:对一个变量的写操作先行发生于后面对这个变量的读操作
2. volatile关键字会强制将修改的值立即写入主存;
3. 当一个线程将共享变量的值修改并将结果同步到主内存当中后,其他线程工作内存当中的缓存值就会失效,即共他线程想再次从自己的工作内存当中读取该变量进行操作时就会失败,而是需要从新从主内存当中读取。当然,如果某个线程已经在自己的自己的工作内存当中读到了该变量的旧值,那么后面操作该变量的值还是以前的值。所以在多个线程对一个变量进行自增时,总是会出现比预期值要小的结果。对示例作了图片化:
示例代码:
public class Test {
public volatile int inc = 0;
public void increase() {
inc++;
}
public static void main(String[] args) {
final Test test = new Test();
for(int i=0;i<10;i++){
new Thread(){
public void run() {
for(int j=0;j<1000;j++)
test.increase();
};
}.start();
}
while(Thread.activeCount()>1) //保证前面的线程都执行完
Thread.yield();
System.out.println(test.inc);
}
}
示例图片:
假如某个时刻,每个线程缓存的变量i的值都是从主内存当中读到的10。
线程1在从自己的缓存当中读到10,还未进行自增操作时线程1被阻塞了;
当然后线程2对变量进行读取并自增,并把11写入工作内存,最后写入到主存。
然后线程1接着进行加1操作,然后将11写入工作内存,最后写入主存。
那么两个线程分别进行了一次自增操作后,i只增加了1。
所以,在多线程下对某个int类型的变量值时,使用volatile没有任何用,Java提供了AtomicInteger这种安全的类型,其他基本类型也有对应的安全类。
volatile关键字适用场景
1.状态标记量
有了它修饰才能中断
volatile boolean flag = false;
while(!flag){
doSomething();
}
public void setFlag() {
flag = true;
}
volatile boolean inited = false;
//线程1:
context = loadContext();
inited = true;
//线程2:
while(!inited ){
sleep()
}
doSomethingwithconfig(context);
2.双重锁
class Singleton{
private volatile static Singleton instance = null;
private Singleton() {
}
public static Singleton getInstance() {
if(instance==null) {
synchronized (Singleton.class) {
if(instance==null)
instance = new Singleton();
}
}
return instance;
}
}