java 可见性简单总结
2018-05-21 10:43 乱月灵猫 阅读(3143) 评论(0) 编辑 收藏 举报Java 可见性
内存模型
- 主存
- 所有线程都可以访问
- 本地内存
- 每个线程私有的内存
- java 的所有变量都存储在主内存中
- 每个线程有自己独的工作内存,保存了该线程使用到的变量副本,是对主内存中变量的一份拷贝
- 每个线程不能访问其他线程的工作内存,线程间变量传递需要通过主内存来完成
- 每个线程不能直接操作主存,只能把主存的内容拷贝到本地内存后再做操作(这是线程不安全的本质),然后写回主存
可见性的方法
volatile
这种方式可以保证每次取数直接从主存取
它只能保证内存的可见性,无法保证原子性
它不需要加锁,比 synchronized 更轻量级,不会阻塞线程
不会被编译器优化
然而要求对这个变量做原子操作,否则还是会有问题
虽然 volatile 是轻量级,但是它也需要保证 读写的顺序不乱序,所以可以有优化点,比如在单例实现方式中的双重校验中,使用 临时变量
降低 volatile 变量的访问。
synchronized
Synchronized 能够实现原子性和可见性;在 Java 内存模型中,synchronized规 定,线程在加锁时,先清空工作内存 → 在主内存中拷贝最新变量的副本到工作内存 → 执行完代码 → 将更改后的共享变量的值刷新到主内存中 → 释放互斥锁。
所以如果无法用 volatile 做可见性,则可以考虑用 synchronized 可以做可见性的保证
AtomicXXX
jdk 提供了很多原子类型,这种类型的基本原理总结起来,volatile + unsafe 的 Compare and Swap,这种 Unsafe 操作并不推荐在自己的代码中使用,因为各 JDK 版本在这里变化较大,有可能升级 JDK 时造成各种问题。而且也要保证自己能够用好。
LongAdder
待补充