ReadWriteLock
416字约1分钟
2024-08-08
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
实例,然后分别获取读锁和写锁
public class Counter {
private final ReadWriteLock rwlock = new ReentrantReadWriteLock();
private final Lock rlock = rwlock.readLock();
private final Lock wlock = rwlock.writeLock();
private int[] counts = new int[10];
public void inc(int index) {
wlock.lock(); // 加写锁
try {
counts[index] += 1;
} finally {
wlock.unlock(); // 释放写锁
}
}
public int[] get() {
rlock.lock(); // 加读锁
try {
return Arrays.copyOf(counts, counts.length);
} finally {
rlock.unlock(); // 释放读锁
}
}
}
把读写操作分别用读锁和写锁来加锁,在读取时,多个线程可以同时获得读锁,这样就大大提高了并发读的执行效率
使用 ReadWriteLock
时,适用条件是同一个数据,有大量线程读取,但仅有少数线程修改