JDK 哪些类底层使用位运算?¶
结论¶
位运算(& | ^ ~ << >> >>>)在 JDK 中被广泛用于节省内存、加速计算。典型场景包括:HashMap 的哈希扰动、线程状态表示、权限/标志位、压缩存储等。
典型应用¶
1. HashMap 的哈希扰动与下标计算¶
// JDK 8 HashMap#hash
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
// 下标 = (n - 1) & hash,用位运算替代取模,速度更快
(n - 1) & hash 要求容量是 2 的幂,这也是 HashMap 容量必须为 2 的幂的原因。
2. ConcurrentHashMap 的状态位¶
ConcurrentHashMap 的 sizeCtl、CounterCell 以及节点的 hash 字段高位,都用位运算来表示:
static final int MOVED = -1; // 正在扩容
static final int TREEBIN = -2; // 树化
static final int RESERVED = -3; // 占位
3. Thread 状态与线程池状态¶
Thread 的 threadStatus、ThreadPoolExecutor 的 ctl 把 workerCount(线程数) 和 runState(运行状态) 塞进一个 int:
private static final int COUNT_BITS = Integer.SIZE - 3; // 29
private static final int CAPACITY = (1 << COUNT_BITS) - 1; // 最大线程数
private static final int RUNNING = -1 << COUNT_BITS;
// 用 ctl & CAPACITY 取线程数,ctl & ~CAPACITY 取状态
4. LongAdder / Striped64¶
用 @sun.misc.Contended 配合 long 值的 CAS,状态判断也大量使用位运算。
5. 包装类与工具类¶
Integer.bitCount(i):统计二进制中 1 的个数(Hack 算法)。Integer.numberOfLeadingZeros:用位移找最高位。Collections、Arrays中的二分查找、HashMap的树化阈值判断。BitSet:本身就是位数组,用long[]的位表示布尔集合。
6. ThreadLocal 的哈希增量¶
// 每个 ThreadLocal 的 threadLocalHashCode 增量为 0x61c88647(黄金分割数)
private static final int HASH_INCREMENT = 0x61c88647;
面试加分
- 位运算比乘除、取模快,且不溢出(
x * 2→x << 1,但编译器通常会做这种优化)。 - 把多个状态压缩进一个 int/long 是 JDK 常见技巧,本质是位域(bit field)思想。