我们先分析读写锁中的这4个int 常量,其实这4个常量的作用就是区分一个int整数的高16位和低16位的,ReentrantReadWriteLock锁还是依托于state变量作为获取锁的标准,那么一个state变量如何区分读锁和写锁呢?答案是通过位运算,高16位表示读锁,低16位表示写锁。如果对位运算不太熟悉或者不了解的同学可以看看这篇文章《位运算》。既然是分析读写锁,那么我们先从读锁和写锁的源码获取入手分析。这里先提前补充一个概念:
写锁和读锁是互斥的(这里的互斥是指线程间的互斥,当前线程可以获取到写锁又获取到读锁,但是获取到了读锁不能继续获取写锁),这是因为读写锁要保持写操作的可见性,如果允许读锁在被获取的情况下对写锁的获取,那么正在运行的其他读线程无法感知到当前写线程的操作。因此,只有等待其他线程都释放了读锁,写锁才能被当前线程获取,而一旦写锁被获取,其他读写线程的后续访问都会被阻塞。
a. 读写锁依托于AQS的State变量的位运算来区分读锁和写锁,高16位表示读锁,低16位表示写锁。
b. 为了保证线程间内容的可见性,读锁和写锁是互斥的,这里的互斥是指线程间的互斥,当前线程可以获取到写锁又获取到读锁,但是获取到了读锁不能继续获取写锁。Sync 同步器位运算分析
我们按照图示内容的数据进行运算,图示的32位二进制数据为:00000000000000100000000000000011
00000000000000100000000000000011 >>> 16,无符号右移16位,结果如下:00000000000000000000000000000010,换算成10进制数等于2,说明读状态为: 2
00000000000000100000000000000011 & 65535,转换成2进制运算为00000000000000100000000000000011 & 00000000000000001111111111111111最后与运算结果为:00000000000000100000000000000011 ,换算成10进制为3
锁降级是指写锁降级为读锁。如果当前线程拥有写锁,然后将其释放,最后再获取读锁,这种分段完成的过程不能称之为锁降级。锁降级是指把持住(之前拥有的写锁的过程)源码示例(来自于《java并发编程的艺术》):public void processData(){ readLock.lock(); if(!update){ //必须先释放读锁 readLock.unlock(); //锁降级从写锁获取到开始 writeLock.lock(); try{ if(!update){ update =true; } readlock.lock(); }finally{ writeLock.unlock(); }//锁降级完成,写锁降级为读锁 } try{ //略 }finally{ readLock.unlock(); }}复制代码上述示例就是一个锁降级的过程,需要注意的是update变量是一个volatie修饰的变量,所以,线程之间是可见的。该代码就是获取到写锁后修改变量,然后获取读锁,获取成功后释放写锁,完成了锁的降级。注意:ReentrantReadWriteLock不支持锁升级,这是因为如果多个线程获取到了读锁,其中任何一个线程获取到了写锁,修改了数据,其他的线程感知不到数据的更新,这样就无法保证数据的可见性。

| 欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) | 黑马程序员IT技术论坛 X3.2 |