synchronized (("" + userId).intern()) { // TODO:something }
JVM內存區域裏面有一塊常量池,關於常量池的分配:java
字符串是存儲在常量池中的,有兩種類型的字符串數據會存儲在常量池中:apache
常量池中的String數據有一個特色:每次取數據的時候,若是常量池中有,直接拿常量池中的數據;若是常量池中沒有,將數據寫入常量池中並返回常量池中的數據。分佈式
這個在jdk6裏問題不算大,由於String.intern()會在perm裏產生空間,若是perm空間夠用的話,這個不會致使頻繁Full GC,優化
可是在jdk7裏問題就大了,String.intern()會在heap裏產生空間,並且仍是老年代,若是對象一多就會致使Full GC時間超長!!!ui
慎用啊!解決辦法?終於找到了。this
這裏要引用強大的google-guava包,這個包不是通常的強大,是徹底要把apache-commons*取締掉的節奏啊!!!google
Interner<String> pool = Interners.newWeakInterner(); synchronized ( pool.intern("BizCode"+userId)){ //TODO:something }
該類對 intern 作了不少的優化,使用弱引用包裝了你傳入的字符串類型,因此,這樣就不會對內存形成較大的影響, 可使用該類的 pool.intern(str) 來進行對字符串intern, 好了,這樣就解決了內存的問題了,那麼咱們使用了該優勢,而且避免了內存佔用問題,完美解決。但這種在分佈式系統中會有問題spa
//類1- SynStringTest package com.tinygao.thread.synstring; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.function.BiConsumer; import com.google.common.base.Stopwatch; import com.google.common.util.concurrent.ThreadFactoryBuilder; import lombok.extern.slf4j.Slf4j; @Slf4j public class SynStringTest { private final static SynString synStr = new SynString(); private final static Stopwatch sw = Stopwatch.createStarted(); private static BiConsumer<SynString, String> function = (x, y)->{ synchronized (x.getStringLock(y)) { log.info("Get lock: {}", y); try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } } }; public static void main(String[] args) throws InterruptedException { final ExecutorService executorService = Executors.newFixedThreadPool( 4, new ThreadFactoryBuilder().setNameFormat("SynString-%d").build() ); executorService.submit(()->{ doTask("test"); }); executorService.submit(()->{ doTask("test"); }); executorService.submit(()->{ doTask("test1"); }); executorService.shutdown(); executorService.awaitTermination(1, TimeUnit.DAYS); sw.stop(); } private static void doTask(String lockStr) { function.accept(synStr, lockStr); log.info("Do get lockStr successed waste time elapsed : {} ms", sw.elapsed(TimeUnit.MILLISECONDS)); } } //類2- SynString package com.tinygao.thread.synstring; import java.util.concurrent.ConcurrentMap; import com.google.common.collect.Maps; import lombok.extern.slf4j.Slf4j; @Slf4j public class SynString { private static ConcurrentMap<String,Object> parMap = Maps.newConcurrentMap(); public Object getStringLock(String string) { Object lock = this; if(parMap != null) { Object newLock = new Object(); lock = parMap.putIfAbsent(string, newLock); if(lock == null) { lock = newLock; } } return lock; } public static void main(String[] args) { Object result = parMap.putIfAbsent("h", "g"); log.info("Get result: {}", result); } }