AQS如何用一个Int值来表示读写两种状态

上一篇博客更新了AQS的一个源码解析,从中我们可以了解到,AQS仅仅依靠一个int值就可以实现线程阻塞排队以及执行的机制。

依赖AQS实现的锁有很多种,ReentrantLock就是其中的一个。下篇博客就是将分析另一种锁ReentrantReadWriteLock。这种锁涉及到写锁与读锁。而AQS仅仅单靠一个int值就区分了读锁。为了理解源码简单,我在这里先将这部分知识点讲解一下。

/*
 * Read vs write count extraction constants and functions.
 * Lock state is logically divided into two unsigned shorts:
 * The lower one representing the exclusive (writer) lock hold count,
 * and the upper the shared (reader) hold count.
 */

static final int SHARED_SHIFT   = 16;
static final int SHARED_UNIT    = (1 << SHARED_SHIFT);
static final int MAX_COUNT      = (1 << SHARED_SHIFT) - 1;
static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;

/** Returns the number of shared holds represented in count  */
static int sharedCount(int c)    { return c >>> SHARED_SHIFT; }
/** Returns the number of exclusive holds represented in count  */
static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }

这一部分代码就是关于AQS使用单一int值表示读锁与写锁两种状态,现在就来分析一下实现的原理吧

首先,我们都知道一个int的值是32位。AQS将这32位分为高16位与低16位两个无符号的short值。(这里我们讨论的都是无符号的数值,下面不再强调)。高是16位用来表示读锁(共享锁),低16位用来表示写锁(独占锁)

 读锁(共享锁)写锁(独占锁)
00000000000000000000000000000000

最大的共享数MAX_COUNT为1左移16位减一,也就是二进制为00000000000000010000000000000000转换成十进制为65536再减去1位65535。同理最大独占数也为65535。

那么AQS又是如何去获取读锁的个数呢? 通过sharedCount(int c) 我们可以知道了解到将一个整数无符号右移16位,从而得到读锁数。具体看下表转换过程

1、假设现在有一个读锁

读锁(共享锁)                          
00000000000000010000000000000000

       2、现在进行读锁个数加一(由于高16位表示读锁,所以每次新增一个读锁,都是在当前状态上加65536

读锁(共享锁) 
00000000000000010000000000000000
00000000000000010000000000000000
00000000000000100000000000000000

 

       3、现在获取读锁个数需进行无符号右移16位,变成如下二进制

读锁(共享锁) 
00000000000000000000000000000010

     将这个二进制转换成十进制可得十进制数2。

这就是读锁的操作过程。接下来看看写锁是如何进行操作的

1、假设现在有一个写锁

写锁(独占锁) 
00000000000000000000000000000001

2、现在进行写锁加1(由于低16位表示写锁,所以每新增一个写锁,都是在当前状态上直接加1

写锁(独占锁) 
00000000000000000000000000000001
00000000000000000000000000000001
00000000000000000000000000000010

3、现在获取写锁的个数,通过exclusiveCount(int c)方法可以知道,将int c与上65535,从而得到写锁个数

写锁(独占锁) 
00000000000000000000000000000010
0000000000000000111111111111111111
00000000000000000000000000000010

 从上可以看到读锁与写锁的操作过程。从这里我们可以看到,AQS在处理读锁与写锁的方式很巧妙,永远把高位的16位变成0,从而消除高位的影响。这里是非常值得借鉴的地方。


PS:这一篇博客的内容介绍是为了下一篇关于ReentrantReadWriteLock的源码阅读进行一个知识补充。由于ReentrantReadWriteLock的内容有点多,我准备分成三到四篇博客进行分析。敬请期待。。。。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值