lamda表达式无法访问外部变量,所以使用final关键字定义一个!!!!!!!!!!
读写锁主要是实现原子操作 读-写 不可以 读-读 可以共存 写-写 不可以
读锁:共享锁 写锁:互斥锁
也没有什么好记的 就是记录一下 读写锁的原理是什么呢?
在Java中通过**ReadWriteLock**来实现读写锁。ReadWriteLock是一个接口,**ReentrantReadWriteLock**是ReadWriteLock接口的具体实现类。
在ReentrantReadWriteLock中定义了两个内部类ReadLock、WriteLock,分别来实现读锁和写锁。
ReentrantReadWriteLock底层是通过**AQS**来实现锁的获取与释放的,因此ReentrantReadWriteLock内部还定义了一个继承了AQS类的同步组件Sync,
同时ReentrantReadWriteLock还支持公平与非公平性,因此它内部还定义了两个内部类FairSync、NonfairSync,它们继承了Sync。
实现原理
在AQS中,通过int类型的全局变量state来表示同步状态,即用state来表示锁。ReentrantReadWriteLock也是通过AQS来实现锁的,但是ReentrantReadWriteLock有两把锁:读锁和写锁,它们保护的都是同一个资源,那么如何用一个共享变量来区分锁是写锁还是读锁呢?答案就是按位拆分。
由于state是int类型的变量,在内存中占用4个字节,也就是32位。将其拆分为两部分:高16位和低16位,其中高16位用来表示读锁状态,低16位用来表示写锁状态。当设置读锁成功时,就将高16位加1,释放读锁时,将高16位减1;当设置写锁成功时,就将低16位加1,释放写锁时,将第16位减1。如下图所示。
将state和0x0000FFFF进行与运算,得到的就是写锁的数量。
读写锁不支持锁升级,支持锁降级。锁升级指的是线程获取到了读锁,在没有释放读锁的前提下,又获取写锁。锁降级指的是线程获取到了写锁,在没有释放写锁的情况下,又获取读锁
public void lockUpgrade(){
ReadWriteLock lock = new ReentrantReadWriteLock();
// 创建读锁
Lock readLock = lock.readLock();
// 创建写锁
Lock writeLock = lock.writeLock();
readLock.lock();
try{
// ...处理业务逻辑
writeLock.lock(); // 代码①
}finally {
readLock.unlock();
}
}
-
1.假如T1线程先获取到了读锁,然后执行后面的代码,在执行到代码①的上一行时,T2线程也去获取读锁,由于读锁是共享锁,且此时写锁还没有被获取,所以此时T2线程可以获取到读锁,当T1执行到代码①时,尝试去获取写锁,由于有T2线程占用了读锁,所以T1线程是无法获取到写锁的,只能等待,当T2也执行到代码①时,由于T1占有了读锁,导致T2无法获取到写锁,这样两个线程就一直等待,即获取不到写锁,也释放不掉读锁。因此锁是不支持锁升级的。 -
2.读写锁支持锁的降级,锁的降级是为了保证可见性。让T1线程对数据的修改对其他线程可见。 -
3.读锁不支持条件等待队列。当调用ReadLock类的newCondition()方法时,会直接抛出异常。