前面讲到的ReentrantLock保证了只有一个线程可以执行临界区代码:
public class Counter {
private final Lock lock = new ReentrantLock(); private int[] counts = new int[10]; public void inc(int index) {
lock.lock(); try {
counts[index] += 1;
} finally {
lock.unlock();
}
} public int[] get() {
lock.lock(); try { return Arrays.copyOf(counts, counts.length);
} finally {
lock.unlock();
}
}
}但是有些时候,这种保护有点过头。因为我们发现,任何时刻,只允许一个线程修改,也就是调用inc()方法是必须获取锁,但是,get()方法只读取数据,不修改数据,它实际上允许多个线程同时调用。
实际上我们想要的是:允许多个线程同时读,但只要有一个线程在写,其他线程就必须等待:
| 读 | 写 | |
|---|---|---|
| 读 | 允许 | 不允许 |
| 写 | 不允许 | 不允许 |
使用ReadWriteLock可以解决这个问题,它保证:
只允许一个线程写入(其他线程既不能写入也不能读取);
没有写入时,多个线程允许同时读(提高性能)。
用ReadWriteLock实现这个功能十分容易。我们需要创建一个ReadWriteLock实例,然后分别获取读锁和写锁: