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

Java Hashtable同步异常:为何无法稳定输出预期值1000?

问题原因解析

Hashtable确实是线程安全的,它的get()和put()方法各自都是同步的,但你代码里的map.put("key", map.get("key")+1)是多个独立同步方法的组合操作,整体不具备原子性。

这个复合操作可以拆成三个独立步骤:

  1. 调用map.get("key")获取当前值
  2. 对获取到的值执行+1运算
  3. 调用map.put()将新值写回

虽然每个步骤单独是线程安全的,但三个步骤之间没有锁的保护,会出现线程交错执行的情况:

  • 线程A执行完步骤1,拿到值为n
  • 此时线程B抢占CPU,也执行步骤1,同样拿到值n
  • 线程A重新获得CPU,完成步骤2和3,把n+1写入Map
  • 线程B接着完成步骤2和3,也把n+1写入Map

这就导致两次操作只让值增加了1,而不是预期的2,最终结果必然小于1000。

修复方案

可以通过以下几种方式保证操作的原子性:

1. 用synchronized块包裹整个复合操作

把get和put的组合操作放到同一个锁块里,确保整个流程是原子的:

Runnable task = () -> {
    for (int i = 0; i < 10; i++) {
        synchronized (map) {
            map.put("key", map.get("key") + 1);
        }
    }
};

2. 使用AtomicInteger作为Map的值

利用原子类的自增方法来保证操作的原子性,避免手动组合操作:

Map<String, AtomicInteger> map = new Hashtable<>();
map.put("key", new AtomicInteger(0));
Runnable task = () -> {
    for (int i = 0; i < 10; i++) {
        map.get("key").incrementAndGet();
    }
};

3. 使用ConcurrentHashMap的原子复合方法

ConcurrentHashMap提供了compute这类原子性的复合操作方法,无需手动加锁:

Map<String, Integer> map = new ConcurrentHashMap<>();
map.put("key", 0);
Runnable task = () -> {
    for (int i = 0; i < 10; i++) {
        map.compute("key", (k, v) -> v + 1);
    }
};

内容的提问来源于stack exchange,提问作者sandeep

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 10:13:09