推荐链接:
总结——》【Java】
总结——》【Mysql】
总结——》【Redis】
总结——》【Kafka】
总结——》【Spring】
总结——》【SpringBoot】
总结——》【MyBatis、MyBatis-Plus】
总结——》【Linux】
总结——》【MongoDB】
总结——》【Elasticsearch】
Java——》可见性
- 一、概念
- 1、可见性问题
- 2、为什么会有可见性问题
- 3、数据同步过程
- 二、在Java中保证可见性的方式
- 1、volatile
- 2、synchronized
- 3、Lock锁
- 4、final
一、概念
可见性是指线程间的,对变量的变化是否可见。通常被解释为将线程本地状态反映到主内存上,volatile就是负责保证可见性的。
1、可见性问题
可见性问题是指一个线程修改了一个共享变量的值,但是另一个线程无法立即看到这个修改后的值。
2、为什么会有可见性问题
CPU处理速度非常快,相对CPU来说,去主内存获取数据这个事情太慢了,CPU就提供了L1,L2,L3的三级缓存,每次去主内存拿完数据后,就会存储到CPU的三级缓存,每次去三级缓存拿数据,效率肯定会提升。
因为每个线程都有自己的工作内存(CPU三级缓存),线程之间无法直接访问对方的工作内存,只改自己的工作内存,没有及时的同步到主内存,导致一个线程对共享变量的修改对其他线程不可见,从而出现数据不一致。
3、数据同步过程
CPU在处理时,需要将主内存数据刷新到寄存器中再执行指令,执行完指令后,再将寄存器数据刷新到主内存中。遵循MESI协议,不是每次操作结束都将CPU缓存数据同步到主内存。
二、在Java中保证可见性的方式
1、volatile
参考链接:Java——》volatile
保证每次CPU操作数据时,修改后的值立即被写回主内存,其他线程在读取该变量时可以直接从主内存中获取最新值
2、synchronized
参考链接:Java——》synchronized保证可见性
确保同一时刻只有一个线程访问共享变量,从而避免了多线程并发访问时对共享变量的竞争和冲突
3、Lock锁
参考链接:Java——》ReentrantLock
4、final
final修饰的属性,在运行期间是不允许修改的,这样一来,就间接的保证了可见性,所有多线程读取final属性,值肯定是一样。
Q:final和volatile不允许同时修饰一个属性?
A:final修饰的内容已经不允许再次被写了,而volatile是保证每次读写数据去主内存读取,并且volatile会影响一定的性能,就不需要同时修饰。