[英]Java String.intern() use HashTable instead of ConcurrentHashMap
我研究String.intern(),這種方法有性能損失。 我將String.intern()與ConcurrentHashMap.putIfAbsent(s,s)與Microbenchmark進行了比較。 使用Java1.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()比ConcurrentHashMap慢,因為String.intern()是本機HashTable實現。 然后,閱讀關於HashTable的javadoc ,這個文檔說:
如果不需要線程安全實現,建議使用HashMap代替Hashtable。 如果需要線程安全的高度並發實現,那么建議使用ConcurrentHashMap代替Hashtable。
這是非常令人困惑的情況。 它推薦使用ConcurrentHashMap,但它使用HashTable雖然性能下降。 有沒有人知道為什么使用ConcurrentHashMap的本機HashTable實現實例?
這里有很多事情要做:
您的基准測試具有非常大的誤差線。 重復計數可能太小了。 這使得結果有問題 。
看起來你的基准測試不會在每次運行1之后重置“interned string”緩存。 這意味着緩存正在增長,每次重復都將以不同的條件開始。 這可以解釋錯誤欄...
您的ConcurrentHashMap
在功能上與String::intern
。 后者使用與Reference
對象相當的本機,以確保可以對已中斷的字符串進行垃圾回收。 你的ConcurrentHashMap
實現沒有。 為什么這很重要?
ConcurrentHashMap
是一個巨大的內存泄漏。 String.intern()比ConcurrentHashMap慢,因為String.intern()是本機HashTable實現。
不是。真正的原因是本機實現的方式不同:
String::intern
時可能會有JNI調用開銷。 請注意,不同Java版本的這些內容差異很大。
這是非常令人困惑的情況。 它推薦使用ConcurrentHashMap,但它使用HashTable雖然性能下降。
現在你談論的是一個與你正在做的事情無關的不同場景。
請注意, String::intern
不使用HashTable
或HashMap
; 往上看。
您找到的引用是關於如何從哈希表中獲得良好的並發性能。 您的基准是(AFAIK)單線程。 對於串行用例, HashMap
將提供比其他用戶更好的性能。
有沒有人知道為什么使用ConcurrentHashMap的本機HashTable實現實例?
它不使用哈希表; 往上看。 有很多原因它不是HashTable
或HashMap
或ConcurrentHashMap
:
Reference
類的內存和CPU開銷很重要。 最后,要小心,你沒有關注這里的錯誤問題。 如果您正在嘗試優化實習,因為它是您的應用程序的瓶頸,另一個策略是根本不實習。 實際上,它很少保存內存(特別是與G1GC的字符串重復數據刪除相比)並且很少提高字符串處理性能。
綜上所述:
String::intern
並未針對速度進行單獨(甚至主要)優化。 1 - 在本土intern
案件中,我認為這是不可能的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.