細粒度鎖:
java中的幾種鎖:synchronized,ReentrantLock,ReentrantReadWriteLock已基本可以滿足編程需求,但其粒度都太大,同一時刻只有一個線程能進入同步塊,這對于某些高并發(fā)的場景并不適用。比如銀行客戶a向b轉(zhuǎn)賬,c向d轉(zhuǎn)賬,假如這兩個線程并發(fā),代碼其實不需要同步。但是同時有線程3,e向b轉(zhuǎn)賬,那么對b而言必須加入同步。這時需要考慮鎖的粒度問題,即細粒度鎖。
網(wǎng)上搜尋了一些關(guān)于java細粒度鎖的介紹文章,大部分是提供思路,比如樂觀鎖,String.intern()和類ConcurrentHashMap,本人對第三種比較感興趣,為此研究了下ConcurrentHashMap的源碼。基于ConcurrentHashMap設(shè)計細粒度大志思路如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
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)如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
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是與具體某個用戶綁定,這里應(yīng)用了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)); } } } |
測試結(jié)果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
-------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 |
測試結(jié)果來看,只有相同userId的線程才會互斥,同步等待;不同userId的線程沒有同步
總結(jié)
以上就是本文關(guān)于java基于ConcurrentHashMap設(shè)計細粒度實現(xiàn)代碼的全部內(nèi)容,希望對大家有所幫助。如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!
原文鏈接:http://www.cnblogs.com/xilijava/p/4569333.html