ReentrantReadWriteLock 使用

Posted by Ink Bai on 2018-10-18, & views

ReentrantReadWriteLock 提供了读写锁机制可以方便我们更好实现并发场景,首先明确读写锁地特征:读锁与读锁不互斥,写锁与读锁互斥,写锁与写锁互斥。

依据此,我们就可以应用在这样地场景下:如果多个线程可以并行跑,那么我们就可以给它们都分配读锁;如果某个线程必须阻塞其他所有线程开跑,那我们就给它设置写锁。

用一个例子来讲解一下,现在共有四个线程,其中三个可以并行跑,一个必须阻塞跑(实际场景如对元数据进行备份,这种情况必须阻塞跑),实现代码如下:

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
object LockExample extends App {
val t1 = new Thread {
override def run(): Unit = {
runWithLock(this.getName ,3000, false)
}
}

val t2 = new Thread {
override def run(): Unit = {
runWithLock(this.getName ,5000, false)
}
}

val t3 = new Thread {
override def run(): Unit = {
runWithLock(this.getName ,7000, false)
}
}

val t4 = new Thread {
override def run(): Unit = {
runWithLock(this.getName ,9000, true)
}
}

private def runWithLock(threadName: String, time: Int, blocking: Boolean) = {
if (!GlobalLockService.acquire(blocking)) {
println("can't get lock!")
}
try {
println(s"enter $threadName")
val start = System.currentTimeMillis()
Thread.sleep(time)
val end = System.currentTimeMillis()
println(s"leave $threadName, spend time: ${(end - start) / 1000}s")
} finally {
GlobalLockService.release(blocking)
}
}

t1.start()
t2.start()
t3.start()
t4.start()
}

object GlobalLockService {
val lock = new ReentrantReadWriteLock()

def acquire(blocking: Boolean) =
if (blocking)
lock.writeLock.tryLock(60, TimeUnit.MINUTES)
else
lock.readLock.tryLock(90, TimeUnit.MINUTES)

def release(blocking: Boolean) =
if (blocking)
lock.writeLock.unlock()
else
lock.readLock.unlock()
}

可能会有多种结果输出:

1
2
3
4
5
6
7
8
enter Thread-0
enter Thread-2
enter Thread-1
leave Thread-0, spend time: 3s
leave Thread-1, spend time: 5s
leave Thread-2, spend time: 7s
enter Thread-3
leave Thread-3, spend time: 9s

或者:

1
2
3
4
5
6
7
8
enter Thread-3
leave Thread-3, spend time: 9s
enter Thread-2
enter Thread-1
enter Thread-0
leave Thread-0, spend time: 3s
leave Thread-1, spend time: 5s
leave Thread-2, spend time: 7s

可以看到线程 0,1,2 都是并发执行,而线程 3 是单独阻塞执行。