java基于ConcurrentHashMap設(shè)計(jì)細(xì)粒度實(shí)現(xiàn)代碼
細(xì)粒度鎖:
java中的幾種鎖:synchronized,ReentrantLock,ReentrantReadWriteLock已基本可以滿足編程需求,但其粒度都太大,同一時(shí)刻只有一個(gè)線程能進(jìn)入同步塊,這對(duì)于某些高并發(fā)的場(chǎng)景并不適用。比如銀行客戶a向b轉(zhuǎn)賬,c向d轉(zhuǎn)賬,假如這兩個(gè)線程并發(fā),代碼其實(shí)不需要同步。但是同時(shí)有線程3,e向b轉(zhuǎn)賬,那么對(duì)b而言必須加入同步。這時(shí)需要考慮鎖的粒度問(wèn)題,即細(xì)粒度鎖。
網(wǎng)上搜尋了一些關(guān)于java細(xì)粒度鎖的介紹文章,大部分是提供思路,比如樂(lè)觀鎖,String.intern()和類(lèi)ConcurrentHashMap,本人對(duì)第三種比較感興趣,為此研究了下ConcurrentHashMap的源碼。基于ConcurrentHashMap設(shè)計(jì)細(xì)粒度大志思路如下:
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 } }
具體實(shí)現(xiàn)如下:
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是與具體某個(gè)用戶綁定,這里應(yīng)用了synchronized(obj)的小技巧,而不是同步當(dāng)前整個(gè)對(duì)象 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)); } } }
測(cè)試結(jié)果:
-------sleep4s--------u2 -------sleep4s--------u1 -------sleep4s--------u3 -------sleep4s--------u4 -------awake----------u2 -------awake----------u3 -------awake----------u1 u2-------moneny----------1 u1-------moneny----------1 -------sleep4s--------u1 u3-------moneny----------1 -------sleep4s--------u2 -------sleep4s--------u3 -------awake----------u4 u4-------moneny----------1 -------awake----------u1 u1-------moneny----------2 -------awake----------u3 u3-------moneny----------2 -------awake----------u2 u2-------moneny----------2 -------sleep4s--------u2 -------awake----------u2 u2-------moneny----------3 -------sleep4s--------u2 -------awake----------u2 u2-------moneny----------4 -------sleep4s--------u2 -------awake----------u2 u2-------moneny----------5 -------sleep4s--------u2 -------awake----------u2 u2-------moneny----------6
測(cè)試結(jié)果來(lái)看,只有相同userId的線程才會(huì)互斥,同步等待;不同userId的線程沒(méi)有同步
總結(jié)
以上就是本文關(guān)于java基于ConcurrentHashMap設(shè)計(jì)細(xì)粒度實(shí)現(xiàn)代碼的全部?jī)?nèi)容,希望對(duì)大家有所幫助。感興趣的朋友可以參閱:權(quán)限控制之粗粒度與細(xì)粒度概念及實(shí)現(xiàn)簡(jiǎn)單介紹、javaweb設(shè)計(jì)中filter粗粒度權(quán)限控制代碼示例等,如有不足之處,歡迎留言指出。感謝朋友們對(duì)本站的支持!
- Java中遍歷ConcurrentHashMap的四種方式詳解
- java 使用ConcurrentHashMap和計(jì)數(shù)器實(shí)現(xiàn)鎖
- Java ConcurrentHashMap的使用示例
- Java源碼解析ConcurrentHashMap的初始化
- java中ConcurrentHashMap的讀操作為什么不需要加鎖
- 基于Java并發(fā)容器ConcurrentHashMap#put方法解析
- java ConcurrentHashMap鎖分段技術(shù)及原理詳解
- Java concurrency集合之ConcurrentHashMap_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
- Java集合ConcurrentHashMap詳解
相關(guān)文章
java?Semaphore共享鎖實(shí)現(xiàn)原理解析
這篇文章主要為大家介紹了Semaphore共享鎖實(shí)現(xiàn)原理解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01Java對(duì)象Serializable接口實(shí)現(xiàn)詳解
這篇文章主要介紹了Java對(duì)象Serializable接口實(shí)現(xiàn)詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12Java的分支結(jié)構(gòu)與循環(huán)你知道多少
這篇文章主要為大家詳細(xì)介紹了Java的分支結(jié)構(gòu)與循環(huán),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助2022-02-02Java使用Scala實(shí)現(xiàn)尾遞歸優(yōu)化來(lái)解決爆棧問(wèn)題
Scala?作為一種多范式的編程語(yǔ)言,結(jié)合了面向?qū)ο蠛秃瘮?shù)式編程的特性,在?Scala?中,尾遞歸?是通過(guò)編譯器優(yōu)化來(lái)防止棧溢出問(wèn)題的,尾遞歸優(yōu)化是一種特殊的優(yōu)化方式,可以讓遞歸調(diào)用不使用新的棧幀,所以本文介紹了在Java項(xiàng)目中如何使用Scala實(shí)現(xiàn)尾遞歸優(yōu)化來(lái)解決爆棧問(wèn)題2024-10-10springMVC利用FastJson接口返回json數(shù)據(jù)相關(guān)配置詳解
本篇文章主要介紹了springMVC利用FastJson接口返回json數(shù)據(jù)相關(guān)配置詳解,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06Java線程池的優(yōu)點(diǎn)及池化技術(shù)的應(yīng)用
這篇文章主要介紹了Java線程池的優(yōu)點(diǎn)及池化技術(shù)的應(yīng)用,Java種提高程序的執(zhí)行效率有兩種實(shí)現(xiàn)方法,一個(gè)是使用線程、另一個(gè)是使用線程池,下文我們就來(lái)具體介紹該詳細(xì)內(nèi)容吧,需要的小伙伴可以參考一下2022-05-05Java java.lang.InstantiationException異常案例詳解
這篇文章主要介紹了Java java.lang.InstantiationException異常案例詳解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08Spring學(xué)習(xí)筆記之bean的基礎(chǔ)知識(shí)
ean在Spring和SpringMVC中無(wú)所不在,將這個(gè)概念內(nèi)化很重要,所以下面這篇文章主要給大家介紹了關(guān)于Spring學(xué)習(xí)筆記之bean基礎(chǔ)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳解,需要的朋友可以參考下。2017-12-12