通用化本地锁实现及用法

简介

针对某些简单场景,如单应用内部数字编号生成逻辑,实现一个简单通用的本地锁。
用以在单应用内部对需要同步的资源对象进行线程安全处理。

设计

获取锁

程序流程图:

说明:

  • 若超过设置的获取锁超时时间,则获取到锁。

核心代码片段

获取锁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public void get(long timeout) {
long start = System.currentTimeMillis();
while (locked.get()) {
try {
TimeUnit.MILLISECONDS.sleep(10);
} catch (Exception e) {
logger.warn(e.getMessage(), e);
}
if (System.currentTimeMillis() - start >= timeout) {
break;
}
}
try {
locked.set(true);
} catch (Exception e) {
logger.warn(e.getMessage(), e);
}
}

释放锁

1
2
3
4
5
6
7
public void release() {
try {
locked.set(false);
} catch (Exception e) {
logger.warn(e.getMessage(), e);
}
}

用法示例

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
public class LockTest {
private static Logger logger = LoggerFactory.getLogger(LockTest.class);
private AtomicBoolean shutdown = new AtomicBoolean(false);

@Test
public void test() throws Exception {
Stack<String> dataStack = new Stack<>();
for (int i = 0; i < 50; i++) {
dataStack.push("" + i);
}
CountDownLatch countDownLatch = new CountDownLatch(dataStack.size());
Lock lock = Lock.create(3000);
List<Thread> threads = new ArrayList<>();
for (int j = 0; j < 10; j++) {
final String threadName = "" + j;
threads.add(new Thread(() -> {
while (!shutdown.get()) {
sleep();
try {
lock.get();
if (!dataStack.isEmpty()) {
String data = dataStack.pop();
System.out.println(String.format("data: %-6s thread: %s", data, threadName));
}
} catch (Exception e) {
logger.warn(e.getMessage(), e);
} finally {
countDownLatch.countDown();
lock.release();
}
}
}, threadName));
}
threads.forEach(Thread::start);
countDownLatch.await();
}

private void sleep() {
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (Exception e) {
logger.debug(e.getMessage(), e);
}
}
}

输出结果

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
data: 47     thread: 4
data: 49 thread: 1
data: 48 thread: 8
data: 46 thread: 9
data: 45 thread: 2
data: 44 thread: 6
data: 43 thread: 7
data: 42 thread: 3
data: 41 thread: 0
data: 40 thread: 5
data: 39 thread: 4
data: 37 thread: 2
data: 38 thread: 9
data: 36 thread: 8
data: 35 thread: 1
data: 34 thread: 6
data: 33 thread: 7
data: 32 thread: 3
data: 31 thread: 0
data: 30 thread: 5
data: 29 thread: 4
data: 27 thread: 9
data: 28 thread: 2
data: 26 thread: 8
data: 25 thread: 7
data: 24 thread: 6
data: 23 thread: 1
data: 22 thread: 3
data: 21 thread: 0
data: 20 thread: 5
data: 19 thread: 4
data: 18 thread: 9
data: 17 thread: 2
data: 16 thread: 7
data: 15 thread: 8
data: 14 thread: 3
data: 12 thread: 6
data: 13 thread: 1
data: 11 thread: 0
data: 10 thread: 5
data: 9 thread: 4
data: 8 thread: 9
data: 7 thread: 2
data: 6 thread: 7
data: 5 thread: 8
data: 3 thread: 1
data: 4 thread: 6
data: 2 thread: 0
data: 1 thread: 3
data: 0 thread: 5

代码仓库

https://github.com/johnsonmoon/commons/blob/master/src/main/java/com/github/johnsonmoon/commons/Lock.java