java基于ConcurrentHashMap設計細粒度實現(xiàn)代碼
細粒度鎖:
java中的幾種鎖:synchronized,ReentrantLock,ReentrantReadWriteLock已基本可以滿足編程需求,但其粒度都太大,同一時刻只有一個線程能進入同步塊,這對于某些高并發(fā)的場景并不適用。比如銀行客戶a向b轉賬,c向d轉賬,假如這兩個線程并發(fā),代碼其實不需要同步。但是同時有線程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
}
}
具體實現(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是與具體某個用戶綁定,這里應用了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----------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
測試結果來看,只有相同userId的線程才會互斥,同步等待;不同userId的線程沒有同步
總結
以上就是本文關于java基于ConcurrentHashMap設計細粒度實現(xiàn)代碼的全部內容,希望對大家有所幫助。感興趣的朋友可以參閱:權限控制之粗粒度與細粒度概念及實現(xiàn)簡單介紹、javaweb設計中filter粗粒度權限控制代碼示例等,如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!
- Java中遍歷ConcurrentHashMap的四種方式詳解
- java 使用ConcurrentHashMap和計數(shù)器實現(xiàn)鎖
- Java ConcurrentHashMap的使用示例
- Java源碼解析ConcurrentHashMap的初始化
- java中ConcurrentHashMap的讀操作為什么不需要加鎖
- 基于Java并發(fā)容器ConcurrentHashMap#put方法解析
- java ConcurrentHashMap鎖分段技術及原理詳解
- Java concurrency集合之ConcurrentHashMap_動力節(jié)點Java學院整理
- Java集合ConcurrentHashMap詳解
相關文章
mybatis中如何實現(xiàn)一個標簽執(zhí)行多個sql語句
這篇文章主要介紹了mybatis中如何實現(xiàn)一個標簽執(zhí)行多個sql語句問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-04-04
java實現(xiàn)動態(tài)編譯并動態(tài)加載
這篇文章主要介紹了java實現(xiàn)動態(tài)編譯并動態(tài)加載,需要的朋友可以參考下2021-04-04
Java8時間api之LocalDate/LocalDateTime的用法詳解
在項目中,時間的使用必不可少,而java8之前的時間api?Date和Calander等在使用上存在著很多問題,于是,jdk1.8引進了新的時間api-LocalDateTime,本文就來講講它的具體使用吧2023-05-05
@MapperScan和@ComponentScan一塊使用導致沖突的解決
這篇文章主要介紹了@MapperScan和@ComponentScan一塊使用導致沖突的解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-11-11
SpringBoot CommandLineRunner應用啟動后執(zhí)行代碼實例
本文將深入探討CommandLineRunner的工作原理、使用場景及最佳實踐,幫助開發(fā)者充分利用這一功能,構建更加健壯的Spring Boot應用,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2025-04-04

