Java并发-1(一)内存可见性

来源:互联网 发布:mac ds store 文件 编辑:程序博客网 时间:2024/06/14 14:58

线程学习之后,大概了解了线程的功能和原理,这里不再赘述。

什么是内存可见性呢?

当若干个线程共享同一个资源的时候,这个资源就处于临界状态,如果处理不当很容易发生一些不愿意看到的错误。

举个栗子:

  1. 创建一个ThreadDemo类实现Runnable接口
  2. 有一个boolean的变量flg默认值是false
  3. 在run()方法中改变flg的值为true
  4. 然后在main方法中创建一个线程执行start方法
  5. 在线程中判断flg的值是否是true,并打印语句
class ThreadDemo implements Runnable{    private  boolean flg = false;    @Override    public void run() {        try {            Thread.sleep(2000);        } catch (InterruptedException e) {            e.printStackTrace();        }        this.flg = true;        System.out.println("ThreadDemo.run()->flg:"+this.flg);    }    public boolean isFlg() {        return flg;    }    public void setFlg(boolean flg) {        this.flg = flg;    }}

TestVolatile类和main方法

public class TestVotile {    public static void main(String[] args) {        ThreadDemo td = new ThreadDemo();        new Thread(td).start();        while(true){            if(td.isFlg()){                System.out.println("CurrentThread->");                break;            }        }    }}

执行main方法之后观察测试结果:

结果令人感到意外?而且发现eclipse上的红色按钮表示程序并没有结束而是一直再循环。

原因分析

在多线程中JVM虚拟机为了优化和提高效率,为每一个线程都提供了一个单独的缓存空间。这样在这个例子中共享变量flg就产生了三个空间,一个是主存,在堆中,另外两个一个在线程td的缓存中,另外一个在main线程的缓存中。

如图所示:
这里写图片描述
在td线程拿到flg之后放在自己的缓存中,并且修改flg为true然后把修改后的值刷新到主内存中,但是由于main线程的while循环效率非常高,在主内存的值被刷新之前就获得到了flg的值,为false,所以不会执行打印语句,即便是主存中的flg值已经被刷新了,但是由于while的影响,没机会在主内存中多的最新的值,导致flg在main的while中一直是false,一直处于循环状态什么都不做。而且主线程也不会结束。

volatile关键字

对于上属于的问题就是内存可见性的问题,在TreadDemo类想flg变量之前加上volatile修饰符,使得双方的操作的共享资源可以及时的得到更新,甚至可以看成双方对共享资源的操作就是指主存中进行的,而且共享资源的的改变可以被任何一个线程得到,这样就保证了内存的可见性。

class ThreadDemo implements Runnable{    private  volatile boolean flg = false;    @Override    public void run() {        try {            Thread.sleep(2000);        } catch (InterruptedException e) {            e.printStackTrace();        }        this.flg = true;        System.out.println("ThreadDemo.run()->flg:"+this.flg);    }    public boolean isFlg() {        return flg;    }    public void setFlg(boolean flg) {        this.flg = flg;    }}

再次测试输出结果为

这里写图片描述

此时线程结束,主线程也打印了语句。

1 0
原创粉丝点击