基本类型局部变量在并发环境下天然具备可见性,因其存储于线程私有栈帧中,彼此隔离、不共享;引用类型变量本身(地址)赋值具有基础可见性,但所指向对象的状态修改需额外保障(如volatile或锁)。

基本类型局部变量在并发环境下天然具备可见性,引用类型则需额外保障。
基本类型局部变量:栈私有,无需同步
方法内声明的基本类型变量(如 int、boolean)存储在每个线程的栈帧中,彼此完全隔离。一个线程对它的读写不会被其他线程感知,也不需要“可见性”机制——因为它本就不共享。
- 例如:
int count = 0;在方法内部累加,每个线程都有自己的副本 - 即使多个线程同时执行同一方法,它们操作的是各自栈上的独立值
- 不存在跨线程读写冲突,JMM 不介入,也无可见性问题
基本类型成员变量:共享但需显式保障可见性
若基本类型是类的实例字段或静态字段(如 private int flag 或 static long version),它就存于堆内存,被多线程共享。此时修改对其他线程是否“立即可见”,取决于是否满足 JMM 的可见性规则。
- 普通字段:写线程更新后,读线程可能仍看到旧值(因 CPU 缓存未刷新、指令重排序等)
- 加
volatile:强制写操作刷新到主内存,读操作从主内存加载,保证可见性 - 用
synchronized或锁:进入/退出临界区时,会触发内存屏障,同样保障可见性
引用类型变量本身:地址可见性 ≠ 对象状态可见性
引用类型变量(如 StringBuilder sb)在栈上存的是对象地址,这个地址的赋值具有原子性和基础可见性;但该地址所指向的堆中对象的状态,是否对其他线程可见,是另一回事。
- 例如:
sb = new StringBuilder();—— 这个赋值动作本身可见(地址更新) - 但
sb.append("a")修改的是堆中对象的内容,若该对象被多个线程共用,其内部字段(如 char[]、count)的修改不自动可见 - 这就是为什么
StringBuilder非线程安全:它没用 volatile 或锁保护内部状态
真正影响并发安全的是“逃逸”与“共享状态”
判断一个变量在并发下是否安全,关键不在它是基本类型还是引用类型,而在于它是否被多个线程访问同一份数据。
- 局部基本类型 → 不逃逸 → 线程私有 → 安全
- 局部引用类型(如 new StringBuilder())→ 不逃逸 → 线程私有 → 安全
- 参数传入的 StringBuilder → 逃逸 → 多线程可能操作同一对象 → 内部状态不可见、不原子 → 不安全
- static final String → 不可变 → 共享但无状态变更 → 安全且可见

















