内存可见性问题 volatile关键字

前言

public class TestVolatile {
    public static void main(String[] args){ //这个线程是用来读取flag的值的
        ThreadDemo threadDemo = new ThreadDemo();
        Thread thread = new Thread(threadDemo);
        // 启动线程
        thread.start();
        // 这里是主线程。
        while (true){
            if (threadDemo.isFlag()){
            System.out.println("主线程读取到的flag = " +
            threadDemo.isFlag());
            break;
            }
        }
    }
}
// 这个线程是用来修改flag的值的
class ThreadDemo implements Runnable{
    public boolean flag = false;
    public boolean isFlag() {
    	return flag;
    }
    @Override
    public void run() {
        try {
        	Thread.sleep(200);
        } catch (InterruptedException e) {
        	e.printStackTrace();
        }
        flag = true;
        System.out.println("ThreadDemo线程修改后的flag = " + isFlag());
    }
}

运行结果是
在这里插入图片描述
这里可以看到另一个线程已经修改了flag变量的值,可是主线程while循环中获取的值确始终是false,这是为什么?
其实是主线程可能会只从其寄存器或本地cache中读取标记变量flag的值,而不是每次都跑去速度更慢的内存里进行操作。基于这个原因,主线程就无法看到另一个线程对其标记变量值的变更了。这也就是内存可见性问题。

内存可见性问题

Java内存模型规定了所有的变量都存储在主内存中。每条线程中还有自己的工作内存,不同工作空间是不可见的。

  • 线程的工作内存会去读取主内存的成员变量并保存副本
  • 线程在工作内存中修改副本
  • 将修改后的副本的值推送给主空间并改写主空间该成员变量的值
  • 主空间成员变量修改后的值将不会主动推送给其他线程, 这就造成了线程的工作内存的共享变量的不同步

如何保证内存可见性

  1. 访问共享资源的代码加synchronized锁,只有当一个线程操作完成后才会有下一个线程来访问共享资源,但是加锁会使程序的效率变低,这样就出现了volatile。
  2. 在共享资源的定义处加volatile。volatile会使得主内存的共享资源每经过一次改变都会推送给其他的线程, 其他线程会修改其副本。

还有一种说法是volatile关键字是告诉JIT编译器,该共享资源可能会被某个线程更改,所以任何对该资源的读写访问都需要忽略本地cache并直接对内存进行操作,共享该变量线程不在工作内存缓存其副本, 所有线程对该变量的操作全是在主内存中完成。即不在存在操作的不可见,所有线程的操作的变量是位于主内存的变量

其他

volatile的底层原理是使用一个叫做“内存栅栏”(Memory Barrier)技术实现,它其实就是从工作内存到主存之间的拷贝动作。

volatile的作用

  • 保证可见性
  • 不保证原子性
  • 禁止指令重排

volatile和synchronized的区别

  • volatile不具备互斥性, 一个线程访问共享变量 , 其他线程也可以访问共享变量。synchronized是互斥锁, 具备互斥性, 在被锁的代码块上只能有一个线程访问共享变量
  • volatile不具备原子性,一个线程在进行一组操作中还没完成时, 其他线程也能进入这组操作对共享变量进行修改。
  • volatile是轻量级的同步策略, 可以修饰基本类型的变量,如int;synchronized是重量级的同步策略,基于对象的同步锁
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值