ReentrantReadWriteLock的进一步分析
ReadWriteLock是接口,我们实现读写锁实质是用接口的实现类ReentrantReadWriteLock
①ReentrantReadWriteLock拥有的特性
1.1获取顺序(公平和非公平)
ReentrantReadWriteLock不会为锁定访问强加读或者写偏向顺序,但是它确实是支持可选的公平策略。
非公平模式(默认)
比公平锁更高的吞吐量。
公平模式
1.2可重入
写锁(写线程)可以在不释放已经拥有的写锁的情况下,重新获取读锁,但是不允许读锁(读线程)获取写锁。
1.3锁降级
可重入特性还允许从写锁降级到读锁—通过获取写锁, 然后获取读锁,然后释放写锁。但是,从读锁到写锁的升级是不可能的。
当前线程拥有写锁,然后将其释放,最后再获取读锁,这种并不能称之为锁降级,锁降级指的是把持住(当前拥有的)写锁,再获取读锁,随后释放(先前有用的)写锁的过程。
通过这种重入,可以减少一步流程释放写锁后 再次获取读锁。
使用了锁降级,就可以减去释放写锁的步骤。直接获取读锁。效率更高。
1.4锁获取的中断
在读锁和写锁的获取过程中支持中断。
1.5支持Condition
写锁提供了Condition实现,RentrantLock. newCondition,读锁不支持Condition,
1.6监控
该类支持确定锁是否持有或争用的方法。这些方法是为了监视系统状态而设计的,而不是用于同步控制。
代码示例
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ThreadTest {
public static void main(String[] args) {
CachedDate cd = new CachedDate();
for (int i = 1; i < 11; i++) {
new Thread(new Runnable() {
@Override
public void run() {
cd.putCachedDate(Thread.currentThread().getName() + "放入的新数据");
}
}, "t" + i).start();
}
}
}
class CachedDate {
private String date = "共享数据变量";
private volatile boolean isUpdate;
private ReadWriteLock rwl = new ReentrantReadWriteLock();
//模拟放置数据到缓存
public void putCachedDate(String date) {
//获得写锁之前,先获得读锁
rwl.readLock().lock();
if (!isUpdate) {//缓存是过期的
rwl.readLock().unlock();//锁不能升级,先用读锁要释放
//获取写锁
rwl.writeLock().lock();
try {
if (!isUpdate) {
//更新缓存
this.date = date;//把写过来的最新数据放入缓存中
isUpdate = true;
}
//拥有写锁的情况下,是可以重入读锁
rwl.readLock().lock();
} finally {
rwl.writeLock().unlock();//同时拥有读锁和写锁,在这里释放写锁,锁降级
}
}
//使用读锁,来缓存
try {
System.out.println("最新的缓存数据打印一下:" + this.date);
} finally {
rwl.readLock().unlock();
}
}
}