java 使用ConcurrentHashMap和計數器實現(xiàn)鎖
在某些場景下,我們想讓線程根據某些業(yè)務數據進行排隊,簡單代碼如下:
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
57
58
59
60
61
62
63
64
65
66
67
|
import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; public class TestServiceImpl { private static ConcurrentHashMap<Long, LockObj> lockMap = new ConcurrentHashMap<Long, LockObj>( 40 ); public void test(Long userId){ LockObj lock = tryLock(userId); synchronized (lock) { try { //處理業(yè)務 } finally { unLock(lock); } } } private LockObj tryLock(Long key) { LockObj curVal = new LockObj(key); LockObj preVal = lockMap.putIfAbsent(key, curVal); if ( null == preVal) { curVal.inc(); return curVal; } else { preVal.inc(); } return preVal; } private void unLock(LockObj lock){ if (lock.dec() <= 0 ){ lockMap.remove(lock.getKey()); } } public class LockObj { private long key = 0 ; private AtomicInteger count = new AtomicInteger( 0 ); public LockObj( long key){ this .key = key; } public int inc(){ return count.incrementAndGet(); } public int dec(){ return count.decrementAndGet(); } public long getKey(){ return key; } @Override public String toString() { return "LockObj [key=" + key + ", count=" + count + "]" ; } } } |
按照userId來排隊,如果每個線程處理數據后不釋放鎖的話,那么可以不利用計數器。但是加了釋放鎖的操作,則必須加上計算器。因為當線程把鎖釋放掉后,還沒來得及退出synchronized 代碼塊時,另外一個線程調用了tryLock方法,那該線程將拿到另外一個對象的鎖,導致利用synchronized 關鍵字進行userId排隊失敗。
也可以利用guava的API來實現(xiàn)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
import com.google.common.collect.Interner; import com.google.common.collect.Interners; public class TestServiceImpl { Interner<String> pool = Interners.newWeakInterner(); public void test(Long userId) throws OspException { synchronized ( pool.intern(String.valueOf(userId))){ //處理業(yè)務操作 } } } |
感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!