跳转至

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 的状态位

ConcurrentHashMapsizeCtlCounterCell 以及节点的 hash 字段高位,都用位运算来表示:

static final int MOVED     = -1;      // 正在扩容
static final int TREEBIN   = -2;      // 树化
static final int RESERVED  = -3;      // 占位

3. Thread 状态与线程池状态

ThreadthreadStatusThreadPoolExecutorctlworkerCount(线程数)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:用位移找最高位。
  • CollectionsArrays 中的二分查找、HashMap 的树化阈值判断。
  • BitSet:本身就是位数组,用 long[] 的位表示布尔集合。

6. ThreadLocal 的哈希增量

// 每个 ThreadLocal 的 threadLocalHashCode 增量为 0x61c88647(黄金分割数)
private static final int HASH_INCREMENT = 0x61c88647;

面试加分

  • 位运算比乘除、取模快,且不溢出(x * 2x << 1,但编译器通常会做这种优化)。
  • 把多个状态压缩进一个 int/long 是 JDK 常见技巧,本质是位域(bit field)思想。