压缩进单个long可行是因为64位足够为多个小范围状态分配互不重叠的bit区域,如tid(16位)、version(16位)、state(2位)、count(30位),总和≤64且无重叠即可无损表示完整状态。

Java 中 CAS 在处理复合逻辑时,常通过“状态压缩”将多个字段打包进一个 long(64 位)变量,再用 AtomicLong.compareAndSet() 一次性完成原子更新。核心在于:**用位运算划分字段空间,确保各状态域互不干扰,且 CAS 操作仍能保持原子性**。
为什么压缩进单个 long 是可行的?
long 占 64 位,足够为多个小范围状态分配独立 bit 区域。例如:
- 线程 ID(tid):用 16 位(最多 65536 个线程)
- 版本号(version):用 16 位(支持 0–65535 次更新)
- 状态标志(state):用 2 位(如 00=空闲、01=运行、10=暂停、11=终止)
- 计数器(count):用 30 位(约 10 亿容量)
只要所有字段总位宽 ≤ 64,且彼此无重叠,就能在一个 long 中无损表示完整状态。
如何安全地读写各字段?
关键靠掩码(mask)和移位(shift)。定义常量明确每个字段起始位和宽度:
立即学习“Java免费学习笔记(深入)”;
private static final int TID_BITS = 16; private static final int VERSION_BITS = 16; private static final int STATE_BITS = 2; private static final int COUNT_BITS = 30; <p>private static final long TID_MASK = (1L << TID_BITS) - 1; private static final long VERSION_MASK = (1L << VERSION_BITS) - 1; private static final long STATE_MASK = (1L << STATE_BITS) - 1; private static final long COUNT_MASK = (1L << COUNT_BITS) - 1;</p><p>private static final int TID_SHIFT = 0; private static final int VERSION_SHIFT = TID_SHIFT + TID_BITS; // 16 private static final int STATE_SHIFT = VERSION_SHIFT + VERSION_BITS; // 32 private static final int COUNT_SHIFT = STATE_SHIFT + STATE_BITS; // 34
读取字段示例:
long state = atomicState.get(); int tid = (int)(state & TID_MASK); int version = (int)((state >> VERSION_SHIFT) & VERSION_MASK); int stateFlag = (int)((state >> STATE_SHIFT) & STATE_MASK); long count = (state >> COUNT_SHIFT) & COUNT_MASK;
构造新状态时,先清空目标区域(用取反掩码 &),再按位或填入新值。
怎么实现一次 CAS 完成复合更新?
典型场景:只有当当前状态满足「tid == 当前线程」且「state == 运行中」时,才把 count 加 1、version 加 1。步骤如下:
- 循环调用
get()获取当前 state 值 - 解析字段,判断是否满足前置条件(如 tid 匹配、state 正确)
- 若满足,构造新 state:用位运算组合新 tid、新 version、相同 state、新 count
- 调用
compareAndSet(oldState, newState) - 失败则重试(乐观策略)
整个过程无锁、无同步块,所有字段变更由一次 CAS 保证原子性——因为修改的是同一个 long 变量。
注意事项与常见陷阱
位操作易出错,需注意:
- 所有掩码必须是
long类型(末尾加L),否则高位会被截断 - 移位超过 31 位时,必须用
>>>(无符号右移)或确保使用long移位,避免 int 自动提升问题 - 字段最大值不能越界(如用 2 位存状态,只允许 0–3;超出会污染相邻字段)
- 如果某字段可能为负数(如带符号计数),需预留符号位或改用无符号解释(Java 8+ 可用
Integer.compareUnsigned类思路)
这种模式广泛用于高性能并发组件,如 StampedLock 的 state 编码、Netty 的 SingleThreadEventExecutor 状态机、自定义有限状态并发队列等。


















