java.util.concurrent.locks包和Read-Write Lock模式

java.util.concurrent.locks包提供了已实现Read-Write Lock模式的ReadWriteLock接口和ReentrantReadWriteLock类。

java.util.concurrent.locks.ReadWriteLock接口的“用于读取的锁”和“用于写入的锁”是通过其他对象来实现的。获取锁和释放锁的方法:

  • readLock.lock()
  • readLock.unlock()
  • writeLock.lock()
  • writeLock.unlock()

java.util.concurrent.locks.ReentrantReadWriteLock类实现了ReadWriteLock接口。ReentrantReadWriteLock类的主要特征如下:

公平性

当创建ReentrantReadWriteLock类的实例时,可以选择锁的获取顺序是否要设为公平(fair)的。如果创建的实例是公平的,那么等待时间久的线程将可以优先获取锁。

可重入性

ReentrantReadWriteLock类的锁是可重入的(reentrant)。也就是说,Reader角色的线程可以获取“用于写入的锁”,Writer角色的线程也可以获取“用于读取的锁”。

锁降级

ReentrantReadWriteLock类可以按如下顺序将“用于写入的锁”降级为“用于读取的锁”:
获取用于写入的锁->获取用于读取的锁->释放用于写入的锁
但是,“用于读取的锁”不可以升级为“用于写入的锁”。

便捷方法

ReentrantReadWriteLock类提供了获取等待中的线程的个数的方法getQueueLength,以及检查是否获取了用于写入的锁的方法isWriteLocked等便捷方法。

使用java.util.concurrent.locks

Data.java

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
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;

public class Data {
private char[] buffer;
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true);
private ReadLock readLock = lock.readLock();
private WriteLock writeLock = lock.writeLock();

public Data(int size) {
this.buffer = new char[size];

for (int i = 0; i < buffer.length; i++) {
buffer[i] = '*';
}
}

public char[] read() throws InterruptedException {
readLock.lock();

try {
return doRead();
} finally {
readLock.unlock();
}
}

public void write(char c) throws InterruptedException {
writeLock.lock();

try {
doWrite(c);
} finally {
writeLock.unlock();
}
}

private char[] doRead() {
char[] newbuf = new char[buffer.length];

for (int i = 0; i < buffer.length; i++) {
newbuf[i] = buffer[i];
}

slowly();
return newbuf;
}

private void doWrite(char c) {
for (int i = 0; i < buffer.length; i++) {
buffer[i] = c;
slowly();
}
}

private void slowly() {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
}
}
}