ReentrantLock的要点总结

1、最主要的三个类Sync、NonfairSync、FairSync。

2、Sync继承了AbstractQueuedSynchronizer,AbstractQueuedSynchronizer继承了AbstractOwnableSynchronizer。
   NonfairSync、FairSync都继承了Sync。

3、Sync的两个最重要的属性为
    1)volatile int state 同步状态:是持有锁的线程数
    2)thread exclusiveOwnerThread:是同步器所持有的线程,即当前持有锁的线程

4、AbstractQueuedSynchronizer维护了一个FIFO队列(双向链表结构),用于存放阻塞线程
  ConditionObject 也维护了一个FIFO队列(双向链表),用于存放状态(waitStatus)为Node.CONDITION的线程节点。

5、AbstractQueuedSynchronizer实际为CLH锁,即 自旋(无限for循环实现)+CAS(unsafe实现)

6、加锁的大致逻辑(公平锁与非公平锁略有不同):两步 加同步状态+入队
    (1)首先线程去获取同步状态(Sync的state属性)。若成功获取同步状态,若为0,则设置同步状态为1(此处,非公平锁会抢占设置同步状态,
        而公平锁倾向于让等待时间更长的线程设置同步状态),并将持有锁的线程设置为当前线程;
        若不为0,则判断是否为当前线程(可重入的实现),若是则将同步状态数加1。
    (2)若获取同步状态失败,则将当前线程封装为一个节点,放入AbstractQueuedSynchronizer的队列尾部。根据节点在尾部的位置不同,做不同的处理。
        如果节点的前置节点为Head,那个会重新尝试获取同步状态,如果获取成功,则将该节点设置为Head;如果失败,再判断其前置节点的状态(waitStatus),如果前置节点
        的状态(waitStatus)为Node.SIGNAL,则需将当前线程阻塞,若前置节点的状态为Node.CANCELLED,则一次将前面状态为Node.CANCELLED的节点移除。
        如果当前线程需要阻塞,则调用LockSupport的park方法(实际上是Unsafe的park方法),如下
        public static void park(Object blocker) {
                Thread t = Thread.currentThread();
                setBlocker(t, blocker);
                UNSAFE.park(false, 0L);
                setBlocker(t, null);
            }
        如果当前线程不需要阻塞,则再次重试获取锁。

7、解锁的大致逻辑:两步 减同步状态+唤醒下一个节点(线程)
    (1)首先是对同步状态的操作(state),每次对state减去指定数值(通常为1,即减去一个线程)。直至state的值为0,将Sync所持有的线程置为null。
    (2)如果同步状态释放成功,则唤醒AbstractQueuedSynchronizer队列中的Head节点(事实上,Head节点为虚节点,实际唤醒的是头节点的下一个节点)。
    (3)唤醒头节点的主要逻辑如下:
        如果头节点的waitStatus<0,即为阻塞状态,需要将waitStatus设置为0.然后获取头节点的下一个节点。若下一个节点为的waitStatus>0(即取消状态),
        则继续寻找直至找到状态waitStaus<=0的节点,然后进行唤醒操作(LockSupport.unpark())。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值