无锁编程中用 atomicinteger 的位运算管理多布尔状态,通过cas原子修改特定位,结合掩码常量和快照读取实现高效、线程安全的状态控制。

CAS 与位运算结合的核心思路
在无锁编程中,直接用 AtomicInteger 或 AtomicLong 存储多个布尔状态,比为每个标志单独建原子变量更省内存、更高效。关键在于:用一个整数的每一位表示一个独立的状态标志(如第 0 位表示“已初始化”,第 1 位表示“正在关闭”,第 2 位表示“暂停中”),再通过 CAS(compareAndSet) 原子地修改特定位,避免读-改-写过程中的竞态。
定义状态位常量与基础操作工具
先约定清晰的位掩码,推荐用 1 定义每位:
- INITIALIZED = 1 → 0b0001
- CLOSING = 1 → 0b0010
- PAUSED = 1 → 0b0100
- ERROR = 1 → 0b1000
用 AtomicInteger state = new AtomicInteger(0) 作为底层存储。所有操作都围绕它展开,不暴露原始值。
原子设置/清除/切换单个标志位
不能直接调用 set() 或 getAndSet(),否则会覆盖其他位。必须用 CAS 循环 + 位运算构造预期值和更新值:
-
设置某位(如启用 PAUSED):
int expect, update;<br> do {<br> expect = state.get();<br> update = expect | PAUSED;<br> } while (!state.compareAndSet(expect, update)); -
清除某位(如取消 CLOSING):
update = expect & ~CLOSING; -
切换某位(取反):
update = expect ^ INITIALIZED;
这种循环 CAS 是标准做法,JDK 8+ 的 AtomicInteger#updateAndGet 可简化为:state.updateAndGet(old -> old | PAUSED); —— 底层仍是 CAS 循环,但语义更清晰。
条件性状态变更(带业务逻辑的原子判断+修改)
例如:“仅当未初始化且未出错时,才允许标记为已初始化”。这需要一次 CAS 完成「检查多条件 + 修改」:
- 预期值:
expect = 0(即 INITIALIZED 和 ERROR 都为 0) - 更新值:
update = INITIALIZED - 但更健壮的做法是显式校验:
int expect = state.get();<br> while ((expect & (INITIALIZED | ERROR)) == 0) {<br> if (state.compareAndSet(expect, expect | INITIALIZED)) break;<br> expect = state.get();<br> }
注意:位与 & 判断多个位是否同时为 0,比逐个 getBit() 更快;用 (a & b) != 0 表示“a 中至少有一位与 b 重叠”,适合判断冲突状态。
安全读取复合状态
读操作本身不需要 CAS,但应避免多次 get() 导致状态不一致。推荐一次性读取当前快照:
-
检查是否已初始化且未暂停:
int s = state.get();<br> boolean ok = (s & INITIALIZED) != 0 && (s & PAUSED) == 0;
- 若需多个相关判断,复用同一个
s,不要反复调用get()。
位运算判断比布尔字段数组或 Map 查找快一个数量级,且无对象分配开销。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











