lock()与lockInterruptibly()
创始人
2025-05-29 08:30:27
0

ReentrantLock相关源码:

    public void lock() {sync.lock();}public void lockInterruptibly() throws InterruptedException {sync.acquireInterruptibly(1);}/*** Sync object for non-fair locks*/static final class NonfairSync extends Sync {private static final long serialVersionUID = 7316153563782823691L;/*** Performs lock.  Try immediate barge, backing up to normal* acquire on failure.*/final void lock() {if (compareAndSetState(0, 1))setExclusiveOwnerThread(Thread.currentThread());elseacquire(1);}protected final boolean tryAcquire(int acquires) {return nonfairTryAcquire(acquires);}}/*** Sync object for fair locks*/static final class FairSync extends Sync {private static final long serialVersionUID = -3000897897090466540L;final void lock() {acquire(1);}/*** Fair version of tryAcquire.  Don't grant access unless* recursive call or no waiters or is first.*/protected final boolean tryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();if (c == 0) {if (!hasQueuedPredecessors() &&compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);return true;}}else if (current == getExclusiveOwnerThread()) {int nextc = c + acquires;if (nextc < 0)throw new Error("Maximum lock count exceeded");setState(nextc);return true;}return false;}}

AbstractQueuedSynchronizer相关源码:

    public final void acquire(int arg) {if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg))selfInterrupt();}public final void acquireInterruptibly(int arg)throws InterruptedException {if (Thread.interrupted())throw new InterruptedException();if (!tryAcquire(arg))doAcquireInterruptibly(arg);}/*** Acquires in exclusive interruptible mode.* @param arg the acquire argument*/private void doAcquireInterruptibly(int arg)throws InterruptedException {final Node node = addWaiter(Node.EXCLUSIVE);boolean failed = true;try {for (;;) {final Node p = node.predecessor();if (p == head && tryAcquire(arg)) {setHead(node);p.next = null; // help GCfailed = false;return;}if (shouldParkAfterFailedAcquire(p, node) &&parkAndCheckInterrupt())throw new InterruptedException();}} finally {if (failed)cancelAcquire(node);}}

通过上面源码可知:

1. lock方法:

lock获取锁过程中,忽略了中断,在成功获取锁之后,再根据中断标识处理中断,即selfInterrupt中断自己。 acquire操作源码如下:

public final void acquire(int arg) {  if (!tryAcquire(arg) &&  acquireQueued(addWaiter(Node.EXCLUSIVE), arg))  selfInterrupt();  }
}

acquireQueued,在for循环中无条件重试获取锁,直到成功获取锁,同时返回线程中断状态。该方法通过for循正常返回时,必定是成功获取到了锁。

    /*** Acquires in exclusive uninterruptible mode for thread already in* queue. Used by condition wait methods as well as acquire.** @param node the node* @param arg the acquire argument* @return {@code true} if interrupted while waiting*/final boolean acquireQueued(final Node node, int arg) {boolean failed = true;try {boolean interrupted = false;for (;;) {final Node p = node.predecessor();if (p == head && tryAcquire(arg)) {setHead(node);p.next = null; // help GCfailed = false;return interrupted;}if (shouldParkAfterFailedAcquire(p, node) &&parkAndCheckInterrupt())interrupted = true;}} finally {if (failed)cancelAcquire(node);}}

2 lockInterruptibly操作

可中断加锁,即在锁获取过程中不处理中断状态,而是直接抛出中断异常,由上层调用者处理中断。源码细微差别在于锁获取这部分代码,这个方法与acquireQueue差别在于方法的返回途径有两种,一种是for循环结束,正常获取到锁;另一种是线程被唤醒后检测到中断请求,则立即抛出中断异常,该操作导致方法结束。

    /*** Acquires in exclusive interruptible mode.* @param arg the acquire argument*/private void doAcquireInterruptibly(int arg)throws InterruptedException {final Node node = addWaiter(Node.EXCLUSIVE);boolean failed = true;try {for (;;) {final Node p = node.predecessor();if (p == head && tryAcquire(arg)) {setHead(node);p.next = null; // help GCfailed = false;return;}if (shouldParkAfterFailedAcquire(p, node) &&parkAndCheckInterrupt())throw new InterruptedException();}} finally {if (failed)cancelAcquire(node);}}

结论:ReentrantLock的中断和非中断加锁模式的区别在于:线程尝试获取锁操作失败后,在等待过程中,如果该线程被其他线程中断了,它是如何响应中断请求的。

lock方法会忽略中断请求,继续获取锁直到成功;而lockInterruptibly则直接抛出中断异常来立即响应中断,由上层调用者处理中断。

那么,为什么要分为这两种模式呢?这两种加锁方式分别适用于什么场合呢?根据它们的实现语义来理解,我认为lock()适用于锁获取操作不受中断影响的情况,此时可以忽略中断请求正常执行加锁操作,因为该操作仅仅记录了中断状态(通过Thread.currentThread().interrupt()操作,只是恢复了中断状态为true,并没有对中断进行响应)。如果要求被中断线程不能参与锁的竞争操作,则此时应该使用lockInterruptibly方法,一旦检测到中断请求,立即返回不再参与锁的竞争并且取消锁获取操作(即finally中的cancelAcquire操作)

相关内容

热门资讯

金观平:宏观政策要持续发力适时... “十四五”规划收官之年,做好下半年经济工作至为关键。 中央政治局日前召开会议,分析研究当前经济形势和...
债券增值税政策刺激公募委外需求... 近日,因增值税政策变化,债券市场出现了明显波动。 短期来看,“新老划断”引发机构抢筹,交易性机会较为...
特朗普重磅发声:可能很快宣布美... 据央视新闻,美国总统特朗普于美国东部时间8月5日,接受了美国消费者新闻与商业频道(CNBC)采访。 ...
珍酒李渡即将推出高端啤酒牛市,... 蓝鲸新闻8月5日讯(记者 朱欣悦)8月4日,珍酒李渡集团董事长吴向东在个人视频平台宣布,将于8月8日...
曼联锁定塞斯科!罗马诺揭秘转会... 在即将到来的新赛季,曼联的转会策略引起了广泛关注。根据著名转会专家罗马诺的最新更新,曼联对签下年轻前...
武平警方奔赴多地,抓获多名犯罪... 武平同城网惠民街本地发布,武平本地信息交流平台加武平微帮 wpwb666--------------...
从“政策红利”到“发展动力”:... 盛夏时节,金川区双湾镇古城村的田间地头,区农业农村局高级农艺师刘光旺正指导农户操作手机客户端,实现精...
最高法发布典型案例 依法严惩医... 8月5日,最高人民法院发布4件人民法院依法严惩医保骗保犯罪典型案例。据悉,各级人民法院依法从严惩处医...
哪天立秋,咋定?立秋后,哪天出... 8月7日13时52分,立秋。这一天何以就是立秋?咋定的?立秋后,距离出伏还有多久? 立秋,与立春、立...
亚洲杯-胡金秋20分赵睿19+... [搜狐体育战报]北京时间8月6日消息,2025年男篮亚洲杯在沙特阿拉伯第二大城市吉达展开首日角逐。C...