您的位置:首页 > 其它

JUC学习--volatile关键字&内存可见性

2018-03-21 17:14 281 查看
学习记录,若存在错误,请指出,谢谢!
首先,介绍一些内存可见性

内存可见性:当多个线程操作共享数据时,彼此不可见
为什么会导致这个情况?
在线程运行的过程中,JVM或者说是内存会为每一个线程分配一个独立的缓存用于提高效率。
举个例子:现在有一个读操作的线程和一个写操作的线程,对主存中的一个共享变量进行操作
写操作:线程先从主存中将共享变量读到线程独有的缓存中,然后对变量的值进行修改,最后再把修改后的变量的值写回到主存中。
读操作:读取主存中共享变量的值
但是,
读线程可能在写线程把修改的变量的值写回主存之前,就从主存中读了变量的值,但是这个值是原先的值public class TestVolatile {

public static void main(String[] args){

ThreadDemo threadDemo = new ThreadDemo();
new Thread(threadDemo).start();

while(true){

if(threadDemo.isFlag()){
System.out.println("--------");
break;
}

}
}

}

class ThreadDemo implements Runnable{

private volatile boolean flag = false;

@Override
public void run() {
try {
Thread.sleep(2000);
}catch (InterruptedException e){
}

flag = true;
System.out.println("flag = " + flag);
}

public boolean isFlag() {
return flag;
}

public void setFlag(boolean flag) {
this.flag = flag;
}
}控制台打印的结果:



这就导致了一个问题,写线程已经把flag的值修改成了true,但是读线程(也就是代码中的main线程)并没有输出“-------”。
于是,我做了以下的修改public class TestVolatile {

public static void main(String[] args){

ThreadDemo threadDemo = new ThreadDemo();
new Thread(threadDemo).start();

while(true){
synchronized (threadDemo){
if(threadDemo.isFlag()){
System.out.println("--------");
break;
}
}
}
}

}在main线程中加上了synchronized关键字。于是



但是,使用了synchronize关键字之后,会导致程序的效率非常的低下。假设程序中有多个线程,每次访问synchronized()这行代码的时候,总是要判断是否有别的线程占有锁,如果有,当前的线程就只能阻塞,直到CPU下次空闲的时候才可能执行。
为了保证程序的效率,就不能够加锁,但是又要解决内存可见性的问题,就要提到volatile关键字了。
volatile关键字:当多个线程对共享数据进行操作时,可以保证该共享数据是内存可见的。
原因是:volatile使用了计算机底层的内存栅栏,可以将线程独立缓存中的值实时更新到主存中去,我们可以理解为,直接对主存进行操作。

当然,使用了volatile关键字也会对系统的性能有一点损耗,因为每进行一次操作,主存中的内容也会相应改变,但是效率比加锁还是要高得多的。private volatile boolean flag = false;将共享变量flag用volatile关键字修饰。



但是,volatile并不能直接替代synchronized关键字,因为相较于synchronized而言,volatile只是一种较为轻量级的同步策略

注意:
volatile不具备“互斥性”;

volatile不能保证“原子性”;
若要满足“互斥性”和“原子性”,则不能使用volatile
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息