本文概要
在AQS(1)中,从ReentrantLock入手,分析了获取和释放锁的源代码;在AQS(2)中,走了一遍Condition条件队列的等待与唤醒。
在两篇文章中,都只是找了典型的几个方法,如ReentrantLock
的lock()
/unlock()
,以及
Condition
的await()
/signal()
。事实上,还有带超时机制,和中断机制的方法,本文就来查漏补缺,大概过一遍
这几个方法。
ReentrantLock
的lock
ReentrantLock
的加锁方法有二:
- lock()
- lockInterruptibly()
顾名思义,一个是可被中断,一个是不可被中断。先来回顾一下不可被中断的:
不可被中断的获取锁方法 lock()
详细分析见AQS1,这里只贴最关键的部分:
1 |
|
什么时候回进入到if
分支呢?就是在排队的时候,如果被唤醒,会去检查一下有没有被中断过,若有的话在获取锁后返回进入该分支。
看一下acquireQueued
方法:
1 |
|
其中selfInterrupt()
方法如下:
1 |
|
就是标记一下中断状态。此时方法的调用者可以去检测一下该中断标记,进行相应处理,也可以啥也不做。
也就是说,中断线程不会影响该线程抢锁。
可被中断的获取锁方法 lockInterruptibly()
二话不说,上代码:
1 |
|
可中断和不可被中断的区别就是:
- 不可被中断:发生中断,仅仅标记中断状态;
- 可中断:发生中断,抛出异常,停止获取锁
再来看一下这个 cancelAcquire
方法吧:
1 |
|
顺便一提的 tryLock()
和 tryLock(long, TimeUnit)
tryLock()
只在锁没有被其他线程持有的时候可以获取,获取不到不排队,返回false。
1 |
|
tryLock(long, TimeUnit)
在超时后会抛出异常来停止获取锁。
1 |
|
Condition
的await
等待方法有四个版本,分别是:
- await():无超时机制,可中断
- awaitNanos(long):有超时机制,可中断
- awaitUntil(Date):有超时机制,可中断
- await(long, TimeUnit):有超时机制,可中断
- awaitUninterruptibly():无超时机制,不可中断
以 awaitNanos(long)
为例来看看带超时机制的代码实现:
1 |
|
不抛出异常的awaitUninterruptibly()
方法:
1 |
|
小结
本文主要讲了AQS
中超时和中断两种情况下的不同方法,简单来说有以下几点:
- 超时机制下,会有一个自旋阈值时间的变量来控制是否要挂起线程,当小于阈值时,自旋性能要更好,也就没必要挂起了;
- 可否中断主要取决于方法对中断信号的处理方式,可以抛出异常来中断在队列中的等待,也可忽略不管