java分段锁示例

Why

读ConcurrentHashMap的时候,我们遇到的一个很大的概念就是Segment(java8之后只有在调用writeObject方法的方法的时候才会用到segment),该类继承了ReentrantLock,用于实现分段锁(乐观锁)。处于心痒痒的目的,我也尝试写了个简陋版的分段锁。

How

该Demo实现的比较简单:根据key获取或者创建Lock(获取锁的时候使用double check),然后使用该锁来同步put或者read(ConcurrentHashMap的读操作使用的volatile,这里不深入)。不足之处还请指正~

What

java实现: github

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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
package com.xiongyingqi.concurrent;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
* @author xiongyingqi
* @version 2016-04-18 16:51
*/
public class MultipleSegmentLock {
private Map<String, ReentrantLock> lockMap = new ConcurrentHashMap<String, ReentrantLock>();

public void write(String key, String value) {
Lock lock = checkLock(key);
lock.lock();
try {
System.out.println("writing... " + key + "=" + value);
try {
// Random random = new Random();
// long time = random.nextInt(10) + 10;
// Thread.sleep(time);
Thread.sleep(10L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("write complete... " + key + "=" + value);
} finally {
lock.unlock();
}
}

public void read(String key) {
Lock lock = checkLock(key);
lock.lock();
try {
System.out.println("reading... " + key);
try {
Thread.sleep(10L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("read complete... " + key);
} finally {
lock.unlock();
}
}

/**
* Getting the lock of the key. Create a {@link ReentrantLock} when not exists.
* <p>Implements with double check</p>
*
* @param key Segment by the key
* @return {@link ReentrantLock}
*/
private Lock checkLock(String key) {
ReentrantLock reentrantLock = lockMap.get(key);
if (reentrantLock == null) {
synchronized (this) {
reentrantLock = lockMap.get(key);
if (reentrantLock == null) {
reentrantLock = new ReentrantLock();
System.out.println(
"lock for " + key + " not exists! so create a lock: " + reentrantLock);
lockMap.put(key, reentrantLock);
return reentrantLock;
}
return reentrantLock;
}
}
return reentrantLock;
}

public static void main(String[] args) {
MultipleSegmentLock multipleSegmentLock = new MultipleSegmentLock();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
multipleSegmentLock.write("key",
"" + i); // synchronous with 'key' and asynchronous with 'key2'
}
}).start();
new Thread(() -> {
for (int i = 100; i < 200; i++) {
multipleSegmentLock.write("key",
"" + i); // synchronous with 'key' and asynchronous with 'key2'
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
multipleSegmentLock.write("key2",
"" + i); // synchronous with 'key2' and asynchronous with 'key'
}
}).start();
new Thread(() -> {
for (int i = 100; i < 200; i++) {
multipleSegmentLock.write("key2",
"" + i); // synchronous with 'key2' and asynchronous with 'key'
}
}).start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
multipleSegmentLock.read("key");
}
}).start();

// Console out may be:
// ----------------------------------------------------
//lock for key not exists! so create a lock: null
//lock for key2 not exists! so create a lock: null
//writing... key=0
//writing... key2=0
//write complete... key=0
//write complete... key2=0
//writing... key=1
//writing... key2=1
//write complete... key=1
//write complete... key2=1
//writing... key2=2
//writing... key=2
//write complete... key2=2
//write complete... key=2
//writing... key2=3
//writing... key=3
//write complete... key2=3
//write complete... key=3
//... ...
//reading... key
//write complete... key2=49
//read complete... key
//reading... key
//writing... key2=50
//read complete... key
//write complete... key2=50
//reading... key
//writing... key2=51
//read complete... key
//write complete... key2=51
//reading... key
//writing... key2=109
//read complete... key
//write complete... key2=109
//reading... key
//writing... key2=110
//read complete... key
//... ...
//writing... key=194
//write complete... key=194
//writing... key=195
//write complete... key=195
//writing... key=196
//write complete... key=196
//writing... key=197
//write complete... key=197
//writing... key=198
//write complete... key=198
//writing... key=199
//write complete... key=199
// ----------------------------------------------------
}

}