1. ReentrantReadWriteLock
一个资源能够被多个读线程访问,或者被一个写线程访问,但是不能同时存在读写线程。
写锁被获取后,可以再次获取写锁或读锁。读锁被获取后,可以再次获取写锁。
- 缺点:1. 写锁饥饿; 2. 锁降级。
2. 写锁饥饿
读锁被持有的时候,写锁会导致一直不能获取,从而产生饥饿。
public class demo06 {
ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
Map<Integer, Integer> map = new HashMap<>();
public void write(int i) {
rwLock.writeLock().lock();
System.out.println(i + " 写入数据中...");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
rwLock.writeLock().unlock();
}
public void read(int i) {
rwLock.readLock().lock();
System.out.println(i + " 读取数据中...");
try {
TimeUnit.MICROSECONDS.sleep(500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
rwLock.readLock().unlock();
}
public static void main(String[] args) {
demo06 d = new demo06();
for(int i=0; i<10; i++) {
int t = i;
new Thread(()->{
d.write(t);
}).start();
}
for(int i=0; i<10; i++) {
int t = i;
new Thread(()->{
d.read(t);
}).start();
}
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
for(int i=0; i<10; i++) {
int t = i;
new Thread(()->{
d.write(t);
}).start();
}
}
}
3. 锁降级
遵循获取写锁、获取读锁再释放写锁的顺序,写锁能够降级为读锁。
读后写是不被允许的。
public static void main(String[] args) {
ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
ReentrantReadWriteLock.WriteLock writeLock = rwLock.writeLock();
ReentrantReadWriteLock.ReadLock readLock = rwLock.readLock();
writeLock.lock();
System.out.println("写...");
readLock.lock();
System.out.println("读...");
writeLock.unlock();
readLock.unlock();
}