`
xumingrencai
  • 浏览: 1180143 次
文章分类
社区版块
存档分类
最新评论

ReentrantLock

 
阅读更多

ReentrantLock是一个互斥的同步器,其实现了接口Lock,里面的功能函数主要有:
1. ‍lock()-- 阻塞模式获取资源
2. ‍lockInterruptibly() -- 可中断模式获取资源
3. ‍tryLock() -- 尝试获取资源
4. tryLock(time) -- 在一段时间内尝试获取资源
5. ‍unlock() -- 释放资源
ReentrantLock实现Lock有两种模式即公平模式和不公平模式


Concurrent包下的同步器都是基于AQS框架,在ReentrantLock里面会看到这样三个类

static abstract class Sync extends AbstractQueuedSynchronizer {
    abstract void lock();
    final boolean nonfairTryAcquire(int acquires) { ... }
    protected final boolean tryRelease(int releases) { ... }
}

final static class NonfairSync extends Sync {
    protected final boolean tryAcquire(int acquires) { ... }
    final void lock() { ... }
}

final static class FairSync extends Sync { 
    final void lock() { ...}
    protected final boolean tryAcquire(int acquires) { ... }
}

再回归到ReentrantLock对Lock的实现上,

0. ‍ReentrantLock实例化
ReentrantLock有个属性sync,实际上对Lock接口的实现都是包装了一下这个sync的实现
如果是公平模式则创建一个FairSync对象,否则创建一个NonfairSync对象,默认是不公平模式


1. lock() 调用sync.lock():
公平模式下:直接走AQS的acquire函数,此函数的逻辑走一次tryAcquire,如果成功: 线程拜托同步器的控制,否则加入NODE链表,进入acquireQueued的tryAcquire,休眠,被唤醒的轮回不公平模式下和公平模式下逻辑大体上是一样的,不同点有两个:
a)在执行tryAcquire之前的操作,不公平模式会直接compareAndSetState(0, 1)原子性的设置AQS的资源,0表示目前没有线程占据资源,则直接抢占资源,不管AQS的NODE链表的FIFO原则
b)tryAcquire的原理不一样,不公平模式的tryAcquire只看compareAndSetState(0, 1)能否成功而公平模式还会加一个条件就是此线程对于的NODE是不是NODE链表的第一个
c)由于tryAcquire的实现不一样,而公平模式和不公平模式在lock期间走的逻辑是一样的(AQS的acquireQueued的逻辑
d)对于一个线程在获取到资源后再调用lock会导致AQS的资源做累加操作,同理线程要彻底的释放资源就必须同样 次数的调用unlock来做对应的累减操作,因为对应ReentrantLock来说tryAcquire成功一个必须的条件就是compareAndSetState(0, 1)
e)由于acquireQueued过程中屏蔽了线程中断,只是在线程拜托同步器控制后,如果记录线程在此期间被中断过则标记线程的中断状态


2. ‍lockInterruptibly() 调用sync.acquireInterruptibly(1),上一篇文章讲过AQS的核心函数,这个过程和acquireQueued是一样的,只不过在阻塞期间如果被标记中断则线程在park期间被唤醒,然后直接退出那个轮回,抛出中断异常
由于公平模式和不公平模式下对tryAcquire的实现不一样导致‍lockInterruptibly逻辑也是不一样


3. tryLock() 函数只是尝试性的去获取一下锁,跟tryAcquire一样,这两种模式下走的代码一样都是公平模式下的代码


4. tryLock(time) 调用sync.tryAcquireNanos(time),上一篇文章讲过AQS的核心函数,这个过程和acquireQueued一样,
a)在阻塞前会先计算阻塞的时间,进入休眠
b) 如果被中断则会判断时间是否到了
1. 如果没到则且被其他线程设置了中断标志,退出那个轮回,抛出中断异常,如果没有被设置中断标记则是前一个线程释放了资源再唤醒了它,其继续走那个轮回,轮回中,如果tryAcquire成功则摆脱了同步器的控制,否则回到
2. 如果时间到了则退出轮回,获取资源失败


5. ‍unlock() 调用sync.release(1),上一篇文章讲过AQS的核心函数,release函数会调用Sync实现的tryRelease函数来判断释放资源是否成功,即Sync.tryRelease函数,其逻辑过程是
a. 首先判断目前占据资源的线程是不是调用者,如果不是会抛出异常IllegalMonitorStateException
b. 如果是则进行AQS资源的减1逻辑,如果再减1后AQS资源变成0则表示调用线程测得放弃了此锁,返回给release的值的TRUE,release会唤醒下一个线程
-----------------------------------------------------------------------
整体来看ReentrantLock互斥锁的实现大致是
1. 自己实现AQS的tryAcquire和tryRelease逻辑,tryAcquire表示尝试去获取锁,tryRelease表示尝试去释放锁
2. ReentrantLock对lock(),trylock(),trylock(time),unlock()的实现都是使用AQS的框架,然后AQS的框架又返回调用ReentrantLock实现的tryAcquire和tryRelease来对线程是否获取锁和释放锁成功做出依据判断

分享到:
评论

相关推荐

    ReentrantLock实现原理详解

    本文将对ReentrantLock实现原理进行详细的介绍,具有很好的参考价值,下面跟着小编一起来看下吧

    教你完全理解ReentrantLock重入锁

    1. ReentrantLock的介绍 ReentrantLock重入锁,是实现Lock接口的一个类,也是在实际编程中使用频率很高的一个锁,支持重入性,表示能够对共享资源能够重复加锁,即当前线程获取该锁再次获取不会被阻塞。在java...

    java ReentrantLock详解.docx

    ReentrantLock java除了使用关键字synchronized外,还可以使用ReentrantLock实现独占锁的功能。而且ReentrantLock相比synchronized而言功能更加丰富,使用起来更为灵活,也更适合复杂的并发场景。这篇文章主要是从...

    ReentrantLock解析

    NULL 博文链接:https://patrick002.iteye.com/blog/2170391

    ReentrantLock.java

    ReentrantLock.java

    使用ReentrantLock和Lambda表达式让同步更

    使用ReentrantLock和Lambda表达式让同步更纯净Java开发Java经验技巧共5页.pdf.zip

    java ReentrantLock详解

    主要介绍了java ReentrantLock,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

    ReentrantLock源码详解--公平锁、非公平锁

    ReentrantLock重入锁,是实现Lock接口的一个类,也是在实际编程中使用频率很高的一个锁,表示能够对共享资源能够重复加锁,即当前线程获取该锁再次获取不会被阻塞。下面我们来深入了解一下它吧

    Java并发之ReentrantLock类源码解析

    主要为大家详细介绍了Java并发系列之ReentrantLock源码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

    ReentrantLock源码详解--条件锁

    主要介绍了ReentrantLock源码之条件锁,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,下面我们来一起学习一下吧

Global site tag (gtag.js) - Google Analytics