差異處
這裏顯示兩個版本的差異處。
java:basic:string_intern [2017/08/19 23:33] |
java:basic:string_intern [2023/06/25 09:48] (目前版本) |
||
---|---|---|---|
行 1: | 行 1: | ||
+ | {{tag>java}} | ||
+ | ====== Synchronized with String intern ====== | ||
+ | ===== Problem ===== | ||
+ | 下面程式碼是相當常見的lazy-instantiation。但在多執行緒存取時,會針對某一相同的key產生多個不同instance。也許最後在map中僅存著一份instance,但如果CreateCache動作耗時或有其它沒預料到的side-effect呢? | ||
+ | <code java> | ||
+ | private volatile Map<String, Object> mCacheMap= new ConcurrentHashMap<String, Object>(); | ||
+ | public Object getCache(String key){ | ||
+ | if(!mCacheMap.contains(key)){ | ||
+ | mCacheMap.put(key, createCache(key)); | ||
+ | } | ||
+ | return mCacheMap.get(key); | ||
+ | } | ||
+ | </code> | ||
+ | 最常見的解法是在method上增加synchronized, | ||
+ | <code java> | ||
+ | public synchronized Object getCache(String key){ | ||
+ | // ... | ||
+ | } | ||
+ | </code> | ||
+ | 或在method內增加synchronized block, | ||
+ | <code java> | ||
+ | public Object getCache(String key){ | ||
+ | synchronized(mCacheMap){ | ||
+ | // ... | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
+ | 上面兩種方式,都屬於不管怎樣就是做同步的控管。但我們只需要針對key相同的情形做控管,才能獲得比較好的效能。 | ||
+ | ===== How to? ===== | ||
+ | String的intern method,可以讓你相同字串但不同物件回傳相同的instance,所以我們"也許"可以寫成這樣: | ||
+ | <code java> | ||
+ | public Object getCache(String key){ | ||
+ | synchronized(key.intern()){ | ||
+ | // ... | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
+ | 但對沒使用過的東西,我無法放100萬個心下來,所以稍微google了這method的資訊。赫然發現,許多的人都不推使用String intern()。觀看intern裡面的實做,最後會呼叫到JVM的native code,因此這實做是綁在JVM上的。詳細可以看[[http://java-performance.info/string-intern-in-java-6-7-8/|這篇]],還包含了效能測試結果。\\ | ||
+ | \\ | ||
+ | 總結裡面的重點是:\\ | ||
+ | - intern建立了一個String Pool。 | ||
+ | - Java6 Pool存在PermGen中,必須將PermGen調大。 | ||
+ | - Java7與8 Pool存在Heap中,效能會受GC與預設pool size影響。 | ||
+ | - 要用intern就是要去tune參數。 | ||
+ | 如果嫌麻煩不想tune JVM參數,裡面也提到自行實做此String pool。而google guava也做了這樣的東西: | ||
+ | <code java> | ||
+ | private Interner<String> mStringInterer = Interners.newWeakInterner(); | ||
+ | |||
+ | public Object getCache(String key){ | ||
+ | synchronized(mStringInterer.intern(key)){ | ||
+ | // ... | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
+ | 它是thread-safe的,你也可以根據自己的需求選擇要使用Weak Reference還是Strong Reference。 | ||
+ | ===== Reference ===== | ||
+ | * [[http://www.javaworld.com/article/2077568/learn-java/java-tip-67--lazy-instantiation.html|lazy-instantiation]] | ||
+ | * [[http://www.tutorialspoint.com/java/java_string_intern.htm|Java String intern]] | ||
+ | * [[http://stackoverflow.com/questions/133988/problem-with-synchronizing-on-string-objects|Problem with synchronizing on string objects]] | ||
+ | * [[http://java-performance.info/string-intern-in-java-6-7-8/|String intern in java 6, 7, 8]] | ||
+ | * [[http://www.cnblogs.com/yhlx/p/3498387.html|在jdk7下慎用String.intern()作为synchronized的对象锁]] | ||
+ | * [[http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/Interners.html|Guava - Interners]] | ||
+ | |||
+ | ===== ===== | ||
+ | ---- | ||
+ | \\ | ||
+ | ~~DISQUS~~ |