Java Hashtable仅方法同步是否会出现put等操作并行执行问题?
Java Hashtable 线程安全问题解答
1. put/putIfAbsent/remove操作是否可以并行运行?
你提到的「Hashtable仅对单个方法做同步,未对table实例变量做同步」是符合实现逻辑的,但这个特性不会导致多个修改操作并行执行:
Hashtable的所有公开成员方法都被synchronized关键字修饰,锁对象为当前Hashtable实例本身。所有修改、读取内部table数组的逻辑都被包裹在这些同步方法中,因此同一个Hashtable实例的任意两个同步方法都无法并行执行:只要有一个线程在执行put方法,其他线程调用putIfAbsent、remove、get等任意同步方法都会进入阻塞状态,直到前一个线程释放实例锁。
2. 为什么还需要其他同步方案实现写入安全?
Hashtable的同步机制仅能保证单个方法调用的原子性,如果业务逻辑涉及复合操作(跨多个方法的逻辑组合),比如「先检查key是否存在,不存在再插入」、「读取旧值后更新为新值」等场景,即使每个方法本身是原子的,组合起来依然会存在竞态条件,无法保证线程安全。
要实现全场景的线程安全,可选择两种主流方案:
- 用
Collections.synchronizedMap包装哈希表:它基于对象级互斥锁实现所有Map操作的同步,你可以基于同一把锁自行封装复合操作的原子逻辑(比如在synchronized (synchronizedMap) {}代码块中执行多步操作) - 直接使用
ConcurrentHashMap:它内置了putIfAbsent、compute、merge等常用复合操作的原子实现,并且JDK8之后采用CAS+分段锁的设计大幅优化了高并发场景下的读写性能,是生产环境的首选方案。
3. 能不能简单判定Hashtable是线程安全的?
不能笼统下结论,需要结合使用场景判断:
如果业务逻辑仅涉及Hashtable单个方法的调用,不存在任何跨方法的复合操作,那Hashtable可以满足线程安全要求;如果涉及复合操作,仅靠Hashtable本身的同步机制无法保证线程安全。
也正是因为这个特性,现在Java官方已经不推荐使用Hashtable,高并发场景优先选择ConcurrentHashMap,低并发需要复合操作的场景可选择Collections.synchronizedMap包装后的实现。
内容的提问来源于stack exchange,提问作者Chintan Mangukiya
相关产品推荐
相关产品推荐

