細粒度鎖:
java/246164.html">java中的幾種鎖:synchronized,ReentrantLock,ReentrantReadWriteLock已基本可以滿足編程需求,但其粒度都太大,同一時刻只有一個線程能進入同步塊,這對于某些高并發的場景并不適用。比如銀行客戶a向b轉賬,c向d轉賬,假如這兩個線程并發,代碼其實不需要同步。但是同時有線程3,e向b轉賬,那么對b而言必須加入同步。這時需要考慮鎖的粒度問題,即細粒度鎖。
網上搜尋了一些關于java細粒度鎖的介紹文章,大部分是提供思路,比如樂觀鎖,String.intern()和類ConcurrentHashMap,本人對第三種比較感興趣,為此研究了下ConcurrentHashMap的源碼。基于ConcurrentHashMap設計細粒度大志思路如下:
Map locks = new Map(); List lockKeys = new List();for (int number : 1 - 10000) { Object lockKey = new Object(); lockKeys.add(lockKey); locks.put(lockKey, new Object());}public void doSomeThing(String uid) { Object lockKey = lockKeys.get(uid.hash() % lockKeys.size()); Object lock = locks.get(lockKey); synchronized(lock) { // do something }}
具體實現如下:
public class LockPool { //用戶map private static ConcurrentHashMap<String,Object> userMap=new ConcurrentHashMap<String,Object>(); //用戶金額map private static ConcurrentHashMap<String,Integer> moneyMap=new ConcurrentHashMap<String,Integer>(); public static void main(String[] args) { LockPool lockPool=new LockPool(); ExecutorService service = Executors.newCachedThreadPool(); service.execute(lockPool.new Boss("u2")); service.execute(lockPool.new Boss("u1")); service.execute(lockPool.new Boss("u1")); service.execute(lockPool.new Boss("u3")); service.execute(lockPool.new Boss("u2")); service.execute(lockPool.new Boss("u2")); service.execute(lockPool.new Boss("u3")); service.execute(lockPool.new Boss("u2")); service.execute(lockPool.new Boss("u2")); service.execute(lockPool.new Boss("u4")); service.execute(lockPool.new Boss("u2")); service.shutdown(); } class Boss implements Runnable{ private String userId; Boss(String userId){ this.userId=userId; } @Override public void run() { addMoney(userId); } } public static void addMoney(String userId){ Object obj=userMap.get(userId); if(obj==null){ obj=new Object(); userMap.put(userId,obj); } //obj是與具體某個用戶綁定,這里應用了synchronized(obj)的小技巧,而不是同步當前整個對象 synchronized (obj) { try { System.out.println("-------sleep4s--------"+userId); Thread.sleep(4000); System.out.println("-------awake----------"+userId); } catch (InterruptedException e) { e.printStackTrace(); } if(moneyMap.get(userId)==null){ moneyMap.put(userId,1); } else{ moneyMap.put(userId, moneyMap.get(userId)+1); } System.out.println(userId+"-------moneny----------"+moneyMap.get(userId)); } }}
測試結果:
-------sleep4s--------u2-------sleep4s--------u1-------sleep4s--------u3-------sleep4s--------u4-------awake----------u2-------awake----------u3-------awake----------u1u2-------moneny----------1u1-------moneny----------1-------sleep4s--------u1u3-------moneny----------1-------sleep4s--------u2-------sleep4s--------u3-------awake----------u4u4-------moneny----------1-------awake----------u1u1-------moneny----------2-------awake----------u3u3-------moneny----------2-------awake----------u2u2-------moneny----------2-------sleep4s--------u2-------awake----------u2u2-------moneny----------3-------sleep4s--------u2-------awake----------u2u2-------moneny----------4-------sleep4s--------u2-------awake----------u2u2-------moneny----------5-------sleep4s--------u2-------awake----------u2u2-------moneny----------6
測試結果來看,只有相同userId的線程才會互斥,同步等待;不同userId的線程沒有同步
總結
以上就是本文關于java基于ConcurrentHashMap設計細粒度實現代碼的全部內容,希望對大家有所幫助。如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!
新聞熱點
疑難解答
圖片精選