java 可见性简单总结

时间:2022-03-07 21:13:30

Java 可见性

内存模型

  • 主存
    • 所有线程都可以访问
  • 本地内存
    • 每个线程私有的内存
- java 的所有变量都存储在主内存中
- 每个线程有自己独的工作内存,保存了该线程使用到的变量副本,是对主内存中变量的一份拷贝
- 每个线程不能访问其他线程的工作内存,线程间变量传递需要通过主内存来完成
- 每个线程不能直接操作主存,只能把主存的内容拷贝到本地内存后再做操作(这是线程不安全的本质),然后写回主存

可见性的方法

volatile

这种方式可以保证每次取数直接从主存取

它只能保证内存的可见性,无法保证原子性

它不需要加锁,比 synchronized 更轻量级,不会阻塞线程

不会被编译器优化

然而要求对这个变量做原子操作,否则还是会有问题

虽然 volatile 是轻量级,但是它也需要保证 读写的顺序不乱序,所以可以有优化点,比如在单例实现方式中的双重校验中,使用 临时变量 降低 volatile 变量的访问。

synchronized

Synchronized 能够实现原子性和可见性;在 Java 内存模型中,synchronized规 定,线程在加锁时,先清空工作内存 → 在主内存中拷贝最新变量的副本到工作内存 → 执行完代码 → 将更改后的共享变量的值刷新到主内存中 → 释放互斥锁。

所以如果无法用 volatile 做可见性,则可以考虑用 synchronized 可以做可见性的保证

AtomicXXX

jdk 提供了很多原子类型,这种类型的基本原理总结起来,volatile + unsafe 的 Compare and Swap,这种 Unsafe 操作并不推荐在自己的代码中使用,因为各 JDK 版本在这里变化较大,有可能升级 JDK 时造成各种问题。而且也要保证自己能够用好。

LongAdder

待补充