volatile 关键字与内存可见性
我们使用多线程的目的是:尽可能的利用CPU资源,提升效率。
当然,如果线程使用不当,会比不使用多线程效率更低,线程创建本身,就需要开销。
Jdk1.5 之后,java.util.concurrent 包,为我们提供了很强大的多线程支持。
首先我们说说 Volatile 关键字,这是为了解决: 内存可见性 问题。
可见性问题,看代码、
public class Volatile {
public static void main(String[] args) {
ThreadDemo td = new ThreadDemo();
new Thread(td).start();
while(true){
if(td.isFlag()){
System.out.println("flag is true now");
break;
}
}
}
}
class ThreadDemo implements Runnable {
private boolean flag = false;
@Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
}
flag = true;
System.out.println("flag=" + isFlag());
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
这段代码的结果是:
flag=true
当线程td改变了flag的值为true,但是,main线程却迟迟不打印 ,因为main线程读取到的flag一直是false。两个线程对共享数据flag的操作,彼此不可见,这就是内存可见性问题。
每个线程启动的时候,JVM会为每一个线程开启独立的缓存空间,用于提高效率。

所以,在main线程的缓存空间中,flag始终是false。
解决方法:
- Synchronize (同步锁)
- volatile 关键字
Synchronize 的作用,是去主存中读数据。
while(true){
//使用synchronize也能搞定。
synchronized (td) {
if(td.isFlag()){
System.out.println("------------------");
break;
}
}
}
输出:
flag is true now flag=true
但是,同步锁synchronize,效率非常低
用Valotile 也可以解决。
private volatile boolean flag = false;
输出相同:
flag is true now flag=true
实际上,Valotile用的是计算机底层的内存栅栏,实时的把数据刷新到主存上。我们可以理解为:只要是volatile 关键字修饰的变量,那么线程就直接在主存中操作数据。
相较于 synchronized 是一种较为轻量级的同步策略
但是,Volatile也有其缺陷: Volatile 不具备互斥性,因此Volatile 也不能保证对象的原子性。

浙公网安备 33010602011771号