多线程中的可见性问题

1.缓存导致的可见性问题

可见性问题是指一个线程修改了某一个共享变量的值时,其他线程是否能够立即知道这个修改。

  • 对于串行程序来说,可见性问题是不存在的,因为你在任何一个操作步骤中修改了某个变量,在后续的步骤中读取这个变量的值时,读取的一定是修改后的新值。
  • 在并行程序中,如果一个线程修改了某一个全局变量,那么其他线程未必可以马上知道这个改动。多核时代,每颗 CPU 都有自己的缓存,这时 CPU 缓存与内存的数据一致性就没那么容易解决了,一个CPU缓存中的变量对另外一个CPU是不可见的
    在这里插入图片描述
    如上图中,两个线程在执行时,CPU1和CPU2分别将内存中的变量,缓存到CPU的cache或者寄存器中,如果CPU1的线程修改了变量V,那么CPU2的线程可能无法意识到这个改动,依然会读取CPU2中cache或者寄存器中的值,这就产生了可见性问题。

2.解决办法

1.使用volatile关键字
volatile 是禁用CPU缓存的意思,变量volatile int x = 0,它表达的是:告诉编译器,对这个变量的读写,不能使用 CPU 缓存,必须从内存中读取或者写入。

2.使用synchronized加锁
JMM(java内存模型)关于synchronized的两条规定:

  • 线程解锁前(退出synchronized代码块之前),必须把共享变量的最新值刷新到主内存中,也就是说线程退出synchronized代码块值后,主内存中保存的共享变量的值已经是最新的了
  • 线程加锁时(进入synchronized代码块之后),将清空工作内存中共享变量的值,从而使用共享变量时需要从主内存中重新读取最新的值(注意:加锁与解锁需要是同一把锁)
  • 两者结合:线程解锁前对共享变量的修改在下次加锁时对其他线程可见

3.synchronizedvolatile的比较

1.volatile不需要加锁,比synchronized更轻量级,不会阻塞线程
2.从内存可见性角度讲,volatile读操作=进入synchronized代码块(加锁),volatile写操作=退出synchronized代码块(解锁)
3.synchronized既能保证可见性,又能保证原子性,而volatile只能保证可见性,不能保证原子性

  • 6
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值