为何String.intern()采用HashTable而非ConcurrentHashMap?性能测试验证
关于String.intern()与ConcurrentHashMap性能对比的疑惑
最近我在研究Java里的String.intern()方法,发现它存在不小的性能损耗。为了搞清楚具体的性能差异,我做了一组微基准测试,对比它和ConcurrentHashMap.putIfAbsent(s,s)的表现。
测试环境
- Java版本:1.8.0_212
- 操作系统:Ubuntu 18.04.2 LTS
测试代码
@Param({"1", "100", "10000", "1000000"}) private int size; private StringIntern stringIntern; private ConcurrentHashMapIntern concurrentHashMapIntern; @Setup public void setup(){ stringIntern = new StringIntern(); concurrentHashMapIntern = new ConcurrentHashMapIntern(); } public static class StringIntern{ public String intern(String s){ return s.intern(); } } public static class ConcurrentHashMapIntern{ private final Map<String, String> map; public ConcurrentHashMapIntern(){ map= new ConcurrentHashMap<>(); } public String intern(String s){ String existString = map.putIfAbsent(s, s); return (existString == null) ? s : existString; } } @Benchmark public void intern(Blackhole blackhole){ for(int count =0; count<size; count ++){ blackhole.consume(stringIntern.intern("Example "+count)); } } @Benchmark public void concurrentHashMapIntern(Blackhole blackhole){ for(int count =0; count<size; count++){ blackhole.consume(concurrentHashMapIntern.intern("Example " +count)); } }
测试结果
测试结果和预期一致,ConcurrentHashMap的实现在字符串查询场景下比String.intern()快得多,尤其是当数据量增大时,性能差距会被进一步放大:
| Benchmark | (size) | Mode | Cnt | Score | Error | Units |
|---|---|---|---|---|---|---|
| MyBenchmark.concurrentHashMapIntern | 1 | avgt | 5 | 0.056 | ± 0.007 | us/op |
| MyBenchmark.concurrentHashMapIntern | 100 | avgt | 5 | 6.094 | ± 2.359 | us/op |
| MyBenchmark.concurrentHashMapIntern | 10000 | avgt | 5 | 787.802 | ± 264.179 | us/op |
| MyBenchmark.concurrentHashMapIntern | 1000000 | avgt | 5 | 136504.010 | ± 17872.866 | us/op |
| MyBenchmark.intern | 1 | avgt | 5 | 0.129 | ± 0.007 | us/op |
| MyBenchmark.intern | 100 | avgt | 5 | 13.700 | ± 2.404 | us/op |
| MyBenchmark.intern | 10000 | avgt | 5 | 1618.514 | ± 460.563 | us/op |
| MyBenchmark.intern | 1000000 | avgt | 5 | 1027915.854 | ± 638910.023 | us/op |
我的困惑
查资料后了解到,String.intern()是基于原生Hashtable实现的。而根据Hashtable的Javadoc明确建议:
- 如果不需要线程安全的实现,推荐用HashMap替代Hashtable;
- 如果需要高并发场景下的线程安全实现,推荐用ConcurrentHashMap替代Hashtable。
这就让我十分不解了:既然官方都推荐在高并发场景下使用ConcurrentHashMap,为什么String.intern()至今仍然采用存在明显性能损耗的Hashtable实现,而不换成ConcurrentHashMap呢?
内容的提问来源于stack exchange,提问作者Turac
相关产品推荐
相关产品推荐

