Java 不可见性的内存语意、不可见性解决——加锁、Volatile修饰

不可见性Volatile


引入:

多个线程访问共享变量,会出现一个线程修改变量的值后,其他线程看不到变量最新值的情况。

结论:

并发编程下,多线程修改变量。公出现战程间变量的不可见性。


不可见性的原因:

每个线程都有自己的工作内存,线程都是从主内存拷贝共享变量的副本值。
每个线程是在自己的工作内存中操作共享变量的。

例如:

下列例子中,flag子线程已经更改为ture,然而却不能进入主线程。是因为每个线程都有自己的工作内存,子线程更改,提交给主内存,但主线程没有从主内存得到新值来更新自己的工作内存

public class Demo1{
    public static void main(String[] args) {
        //子线程启动
        vision t1 = new vision();
        t1.start();

        //主线程
        while(true){
            if (t1.isFlag()){
                System.out.println("主线程进入执行");
            }
        }
    }
}

class vision extends Thread{
    private boolean flag = false;
    public boolean isFlag() {
        return flag;
    }
    public void setFlag(boolean flag) {
        this.flag = flag;
    }
    @Override
    public void run() {
        try {
            Thread.sleep(10000);
        }catch (Exception e){
            e.printStackTrace();
        }
        flag = true;
        System.out.println(flag);
    }
}

不可见性的解决 :

解决方案有两种常见方式:

  1. 加锁
  2. 对共享的变量进行volatile关键字修饰。

一、加锁

某一个线程进入synchronized代码块前后,执行过程入如下:

  • a. 线程获得锁
  • b. 清空工作内存
  • c. 从主内存拷贝共享变量最新的值到工作内存成为副本
  • d. 执行代码
  • e. 将修改后的副本的值刷新回主内存中
  • f. 线程释放锁
        //子线程启动
        vision2 t1 = new vision2();
        t1.start();

        //主线程
        while(true){
        //加锁会清空工作内存,读取主内存最新值到工作内存来
            synchronized(vision2.class){
                if (t1.isFlag()){
                    System.out.println("主线程进入执行");
                }
            }
        }

二、volatile修饰

直接给变量加上volatile修饰

class vision2 extends Thread{
    private volatile boolean flag = false;
    public boolean isFlag() {
        return flag;
    }
    public void setFlag(boolean flag) {
        this.flag = flag;
    }
    @Override
    public void run() {
        try {
            Thread.sleep(10000);
        }catch (Exception e){
            e.printStackTrace();
        }
        flag = true;
        System.out.println(flag);
    }
}
  1. 子线程从主内存读取到数据放入其对应的工作内存
  2. 将flag的值更改为true,但是这个时候flag的值还没有写到主内存
  3. 此时main方法main方法读取到了flag的值为false
  4. 当子线程将flag的值写回去后,失效其他线程对此变量副本
  5. 再次对flag进行操作的时候线程会从主内存读取最新的值,放入到工作内存中

总结:

  • volatile保证不同线程对共享变量操作的可见性,也就是说一个线程修改了volatile修饰的变量, 当修改写回主内存时,另外一个线程立即看到最新的值。

  • 加锁会清空线程自己的工作内存,重新读取主内存的最新值。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值