java中基本类型(boolean、byte、short、char、int、float)和引用类型的直接赋值是原子操作;volatile修饰的long/double赋值也是原子的,但i++、y=x等含读-改-写步骤的操作非原子。

Java中变量赋值是否具有原子性,不能一概而论——它取决于数据类型、JVM实现、是否volatile修饰,以及是否涉及多线程竞争。
哪些赋值操作是原子的
在绝大多数现代JVM(包括JDK 8及以后版本)上:
-
基本类型(boolean、byte、short、char、int、float)的读取和直接赋值是原子操作,例如
int x = 5;或boolean flag = true; -
所有引用类型(reference)的赋值也是原子的,无论对象大小,例如
String s = "hello";或List<string> list = new ArrayList();</string> - 被 volatile 修饰的 long 和 double 赋值是原子的;否则,在部分旧JVM或特定平台(如某些32位环境)下,64位值可能被拆成两次32位写入,存在“半个值”风险
哪些看似赋值,其实不是原子操作
表面像赋值,实则包含“读-改-写”三步,天然非原子:
-
i++:先读 i,再加1,最后写回 i -
i += 1、i = i + 1:同上,含读取、计算、赋值三个独立步骤 -
y = x:虽然目标是赋值,但它依赖先读 x 的值,再写给 y —— 两个原子动作组合后整体不保证原子性 -
obj.field = value(非volatile字段):字段写入本身可能是原子的,但若涉及内存可见性问题,其他线程仍可能看不到最新值
多线程下怎么安全处理赋值
单靠“赋值是原子的”不足以保障线程安全,还需兼顾可见性与执行顺序:
- 对共享计数器等场景,优先用
AtomicInteger等原子类,它们底层用CAS指令,既原子又可见 - 若需复合逻辑(如“先检查再赋值”),必须用
synchronized或ReentrantLock包裹整个临界区 - 仅需保证修改对其他线程立即可见时,用
volatile即可,比如开关标志位volatile boolean running = true; - 不要依赖“int赋值是原子的”就省略同步——原子性 ≠ 线程安全,缺少可见性或有序性仍会出错
一个典型误区提醒
有人认为 int x = 0; 是原子的,所以多个线程同时执行 x = 1; 就不会出问题。这是错的:虽然每次赋值动作本身原子,但多个线程并发写同一变量,没有同步机制时,最终结果不可预测(可能丢失写入、无法保证谁的值胜出),且其他线程也不一定及时看到该值——这已超出原子性范畴,进入可见性与竞态控制领域。











