第六章 ReentrantLock源码解析2--释放锁unlock()

最常用的方式:

复制代码
        int a = 12;
        //注意:通常情况下,这个会设置成一个类变量,比如说Segement中的段锁与copyOnWriteArrayList中的全局锁
        final ReentrantLock lock = new ReentrantLock();
        
        lock.lock();//获取锁
        try {
            a++;//业务逻辑
        } catch (Exception e) {
        }finally{
            lock.unlock();//释放锁
        }
复制代码

注:关于lock()方法的源码解析,请参照"第五章 ReentrantLock源码解析1--获得非公平锁与公平锁lock()",具体链接如下:

http://www.cnblogs.com/java-zhao/p/5131544.html

 

释放锁:unlock()

步骤:

1)获取当前的锁数量,然后用这个锁数量减去解锁的数量(这里为1),最后得出结果c

2)判断当前线程是不是独占锁的线程,如果不是,抛出异常

3)如果c==0,说明锁被成功释放,将当前的独占线程置为null,锁数量置为0,返回true

4)如果c!=0,说明释放锁失败,锁数量置为c,返回false

5)如果锁被释放成功的话,唤醒距离头节点最近的一个非取消的节点

源代码:

 ReentrantLock:unlock()

  View Code

AbstractQueuedSynchronizer:release(int arg)

  View Code

Sync:tryRelease(int releases)

  View Code

AbstractQueuedSynchronizer:unparkSuccessor(Node node)

  View Code

 

注意:

在程序的注释部分有一些疑问,整理成下边这样:

  • 如果按照开头的那个程序的话,成功的获取一个锁之后,就会在finally里边解一次锁,可重入性怎么体现?
  • 在找到离头节点最近的一个非取消的节点,是以从后往前的方式进行的,原因是"从后往前遍历据说是在入队(enq())的时候,可能nodeX.next==null",但是在读源码的时候没看出来

 第一个问题答案:

可重入性体现在下边这个程序(就是锁套锁,最常见的就是在递归中):

  View Code

注意:

  • 上边这个程序只是一个示例,在递归的使用中,一定要有递归结束的条件
  • 每有一个lock()方法,就有一个unlock()与之对应,所以在解锁的时候,只需要把传递解锁数量为1就可以。

第二个问题答案:

记住:如果顺着节点头一直next下去可能会不正确。
举个例子:A1->A2->A3
现在我们从A1开始往下走,当我们走到A3的时候,就在这时,一个新节点A4入队,会走下面的入队代码:

可以看到步骤1和步骤2整体并不是原子的,也就是说,当执行完CAS的时候但是2还没执行,这时候队列为:A1-->A2-->A4,如果你使用next的话,可能就把A3给没了,但是node.prev = t(即A4.prev = A3),也就是说前驱节点是已经赋过值了的,如果你从队列结尾A4.prev就会是A3,即A3也丢不了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值