You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何无锁场景下BitSet执行set()会出现(false,true)或(true,false)结果?

为什么BitSet多线程无锁set会出现读取不一致?

核心原因是BitSet的set()方法并非原子操作——哪怕底层位运算本身是原子的,整个操作流程仍存在竞态条件。

具体分析步骤:

BitSet底层用long[] words存储位信息,bit1和bit2都落在同一个long元素(words[0])里。set(int bitIndex)的核心逻辑大致如下:

int wordIndex = bitIndex >> 6; // 计算对应long数组下标
long oldValue = words[wordIndex];
long newValue = oldValue | (1L << bitIndex);
words[wordIndex] = newValue;

(实际源码包含扩容检查,但核心读写逻辑一致)

当两个线程同时操作同一个long元素时,会发生以下典型时序:

  1. 线程1读取words[0]的初始值0
  2. 线程2也读取words[0]的初始值0
  3. 线程1计算得到0 | (1<<1) = 2,并写回words[0]
  4. 线程2计算得到0 | (1<<2) = 4,并写回words[0]

最终words[0]的值是4,导致bit1为false、bit2为true;反之如果线程2先写回,就会出现bit1为true、bit2为false的情况。

关键误区:

你以为位运算(|=)是原子的就不会有问题,但|=本质上是读-改-写的组合操作,这三步整体没有同步保护,多个线程并发执行时会互相覆盖修改。另外需要注意,BitSet的words数组并非volatile,线程间内存可见性无法保证,但在这个场景里,第三个线程等待前两个线程终止后读取,核心问题还是竞态条件导致的覆盖,而非可见性。

解决方案:

  • 对BitSet的所有操作加锁(比如synchronized块)
  • 使用Collections.synchronizedBitSet()包装BitSet,获得线程安全的实现
  • 如果是JDK 9+,可以考虑使用VarHandle实现原子的位修改操作

内容的提问来源于stack exchange,提问作者ng.newbie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 07:57:26