Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >什么是可中断锁?有什么用?怎么实现?

什么是可中断锁?有什么用?怎么实现?

作者头像
磊哥
发布于 2021-09-14 02:54:13
发布于 2021-09-14 02:54:13
1K00
代码可运行
举报
文章被收录于专栏:王磊的博客王磊的博客
运行总次数:0
代码可运行

在 Java 中有两种锁,一种是内置锁 synchronized,一种是显示锁 Lock,其中 Lock 锁是可中断锁,而 synchronized 则为不可中断锁。 ​

所谓的中断锁指的是锁在执行时可被中断,也就是在执行时可以接收 interrupt 的通知,从而中断锁执行。 ​

PS:默认情况下 Lock 也是不可中断锁,但是可以通过特殊的“手段”,可以让其变为可中断锁,接下来我们一起来看。

为什么需要可中断锁?

不可中断锁的问题是,当出现“异常”时,只能一直阻塞等待,别无其他办法,比如下面这个程序。下面的这个程序中有两个线程,其中线程 1 先获取到锁资源执行相应代码,而线程 2 在 0.5s 之后开始尝试获取锁资源,但线程 1 执行时忘记释放锁了,这就造成线程 2 一直阻塞等待的情况,实现代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class InterruptiblyExample {
    public static void main(String[] args) {
        Lock lock = new ReentrantLock();

        // 创建线程 1
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                lock.lock();
                System.out.println("线程 1:获取到锁.");
                // 线程 1 未释放锁
            }
        });
        t1.start();

        // 创建线程 2
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                // 先休眠 0.5s,让线程 1 先执行
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 获取锁
                System.out.println("线程 2:等待获取锁.");
                lock.lock();
                try {
                    System.out.println("线程 2:获取锁成功.");
                } finally {
                    lock.unlock();
                }
            }
        });
        t2.start();
    }
}

以上代码执行的结果如下:

从上述结果可以看出,此时线程 2 在等待获取锁的操作,然而经历了 N 久之后...

再次查看结果,依然是熟悉的画面:

线程 2 还在阻塞等待获取线程 1 释放锁资源,此时的线程 2 除了等之外,并无其他方法。 ​

并且,但我们熟练的拿出了 JConsole,试图得到一个死锁的具体信息时,却得到了这样的结果:

并没有检测到任何死锁信息,从上图我们可以看出,当只有一个锁资源的时候,系统并不会把这种情况判定为死锁,当然也没有阻塞等待的具体信息喽,此时只剩下线程 2 孤单地等待着它的“锁儿”。

使用中断锁

然而,中断锁的出现,就可以打破这一僵局,它可以在等待一定时间之后,主动的中断线程 2,以解决线程阻塞等待的问题。 ​

中断锁的核心实现代码是 lock.lockInterruptibly() 方法,它和 lock.lock() 方法作用类似,只不过使用 lockInterruptibly 方法可以优先接收中断的请求,中断锁的具体实现如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class InterruptiblyExample {
    public static void main(String[] args) throws InterruptedException {
        Lock lock = new ReentrantLock();

        // 创建线程 1
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    // 加锁操作
                    lock.lock();
                    System.out.println("线程 1:获取到锁.");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 线程 1 未释放锁
            }
        });
        t1.start();

        // 创建线程 2
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                // 先休眠 0.5s,让线程 1 先执行
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 获取锁
                try {
                    System.out.println("线程 2:尝试获取锁.");
                    lock.lockInterruptibly(); // 可中断锁
                    System.out.println("线程 2:获取锁成功.");
                } catch (InterruptedException e) {
                    System.out.println("线程 2:执行已被中断.");
                }
            }
        });
        t2.start();

        // 等待 2s 后,终止线程 2
        Thread.sleep(2000);
        if (t2.isAlive()) { // 线程 2 还在执行
            System.out.println("执行线程的中断.");
            t2.interrupt();
        } else {
            System.out.println("线程 2:执行完成.");
        }
    }
}

以上代码执行结果如下:

从上述结果可以看出,当我们使用了 lockInterruptibly 方法就可以在一段时间之后,判断它是否还在阻塞等待,如果结果为真,就可以直接将他中断,如上图效果所示。 ​

但当我们尝试将 lockInterruptibly 方法换成 lock 方法之后(其他代码都不变),执行的结果就完全不一样了,实现代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class InterruptiblyExample {
    public static void main(String[] args) throws InterruptedException {
        Lock lock = new ReentrantLock();

        // 创建线程 1
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    // 加锁操作
                    lock.lockInterruptibly();
                    System.out.println("线程 1:获取到锁.");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 线程 1 未释放锁
            }
        });
        t1.start();

        // 创建线程 2
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                // 先休眠 0.5s,让线程 1 先执行
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 获取锁
                try {
                    System.out.println("线程 2:尝试获取锁.");
                    lock.lock();
                    System.out.println("线程 2:获取锁成功.");
                } catch (Exception e) {
                    System.out.println("线程 2:执行已被中断.");
                }
            }
        });
        t2.start();

        // 等待 2s 后,终止线程 2
        Thread.sleep(2000);
        if (t2.isAlive()) { // 线程 2 还在执行
            System.out.println("执行线程的中断.");
            t2.interrupt();
        } else {
            System.out.println("线程 2:执行完成.");
        }
    }
}

以上程序执行结果如下:

从上图可以看出,当使用 lock 方法时,即使调用了 interrupt 方法依然不能将线程 2 进行中断。

总结

本文介绍了中断锁的实现,通过显示锁 Lock 的 lockInterruptibly 方法来完成,它和 lock 方法作用类似,但 lockInterruptibly 可以优先接收到中断的通知,而 lock 方法只能“死等”锁资源的释放,同时这两个方法的区别也是常见的面试题,希望本文对你有用。 ​

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-09-10 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
利用Word制作简易版的电子签名
在日常工作生活中呢,我们常常接到紧急任务,XXX 你马上给我XX文件的签名扫描件,这上哪弄去啊,不慌,这时候我们可以用Word制作简易的电子签名照!
浩Coding
2021/01/15
3.6K0
利用Word制作简易版的电子签名
电子签名的制作和使用方法_如何使用电子签名
这里透明色是为了去除干扰,因为只做黑白处理之后,有的字会模糊,也就是背景中有污渍,用此操作可以去除污渍。
全栈程序员站长
2022/11/03
3.9K0
电子签名的制作和使用方法_如何使用电子签名
word封面背景及水印背景
制作封面 在制作商业项目申报书的时候我们想要封面尽可能美观,常用的方法是使用插入一张很大的图片作为背景。 标题等文本则通过文本框的格式添加到图片上 直接使用图片将背景遮住就行 下图是一个设计好后的背景
演化计算与人工智能
2020/08/14
1.1K0
word封面背景及水印背景
如何使用PS简单抠图
哈喽!各位小伙伴大家好呀! 之前写到了制作电子邀请函,本期就来说说如何制作一些素材, 也就是如何用PS抠图,看见一些好的图也能自己抠了。 开始之前当然是需要软件了,小编演示是用的PS 2015 64位
简单并不简单
2019/09/09
2.6K0
WORD的基本操作(五)
鼠标指针放在所需插入图片的位置---插入---图片---打开插入图片对话框---选择图片---单击插入
用户5410712
2022/06/01
1.2K0
WORD的基本操作(五)
20种常用的 Ps技术
一种简单的数码照片后期润饰 1 打开图片,执行色像/饱和度(-40)降低饱和度。 2 新建一图层,将图层模式改为柔光,用画笔工具将需要润饰的部分画几下,这里可以利用色板方便的提取颜色 3 图片色彩过渡不够柔和,再执行一下滤镜下面的高斯模糊(+85)
WindCoder
2018/09/20
2.7K0
Word写作 | 如何在Word中把图片铺满整个页面
只要在 Word 中设置图片布局选项的文字环绕,调整为衬于文字下方、浮于文字上方或者中间居中等样式(除【嵌入型】以外的其他形式),然后就可以任意移动放大将整张图片铺满整个页面。具体操作如下:
叶庭云
2022/05/09
2.4K0
Word写作 | 如何在Word中把图片铺满整个页面
ps快捷键
基础操作: ctrl+0=显示全图; ctrl+=放大; ctrl-=缩小; ctrl+j:复制当前图层到一个新层 ; ctrl+1 =实际像素显示。
mcxfate
2020/08/01
4.3K0
PPT图片都有哪些处理方式
我们在制作PPT的时候常常需要用到图片,图片能更好的辅助我们传达信息,也能让PPT更加赏心悦目。但我们常常只是把图片放到PPT里就完事儿了,忽略了对图片的细节处理。殊不知,未加处理的图片可能会让你精心制作的PPT大大减分。今天,我们就来讲讲如何处理PPT中的图片!
纸醉金迷i
2021/12/25
1.1K0
PPT图片都有哪些处理方式
【如何写论文】解决方案——删除脚注里多余的回车换行,标题的段前磅数消失问题、图像显示不完整、被截断、浮动问题
这里可以把多余换行符进行删除然后再次点击显示备注关闭窗口,点击视图-页面视图,回归正常编辑流程。
中杯可乐多加冰
2024/09/22
5660
怎么用Word制作排班表,手把手教你学会
在工作中,或者是在生活中,人们听到排班表的时候,一点也不会感觉惊讶,因为这是在工作中的需要,日常的工作都会有班次的安排,根据不同的情况给每个人安排不同的时间段来进行工作,例如早班,中班,晚班,为了让大家更加了解自己是什么时候工作,就需要制作一个排班表,那么怎么用Word制作排班表?今天就来给大家分享一下,这个简单的方法,手把手教你学会哦。
高效办公
2019/03/08
3.6K0
怎么用Word制作排班表,手把手教你学会
word 电子签名
适用于需要对 PDF 和 word 进行签名的情况 图片处理 准备手写的签名图片 打开在线 P 图网站[1](会用 PS 就用 PS),打开图片 使用 裁剪工具 框中后双击 将图片裁剪成适当大小,即尽
演化计算与人工智能
2020/08/14
1.5K0
word 电子签名
PS脚本案例
IT工作者
2023/09/01
1.3K0
妙用Ps计算工具调出另类色调PS全版本软件下载地址包括最新的2023
通过本教程你将会学到怎样利用计算工具来创建一个新的阿尔法通道,并调整出很别致的图片颜色效果。
木子学Lee
2023/02/26
4380
妙用Ps计算工具调出另类色调PS全版本软件下载地址包括最新的2023
一篇文章带你了解HTML语法
在做web开发时,我们必不可少的要使用到Html,因为它包含了最基础的网页结构,虽然Html只能帮助我们构建静态网页,但是却是我们最不能缺少的部分,如果把网页比作一个房子,那么Html就是地基,也就是第一件要做的事,可见它的重要性。那么,现在大家就跟随我的脚步去学习下吧。
前端皮皮
2020/11/26
2.7K0
一篇文章带你了解HTML语法
如何将标签上的文本转换成黑底白字
大家在使用条码软件制作标签时,添加的文字内容一般都是白底黑字的,或者是其他颜色的,但是有一些用户需要实现黑底白字的效果。下面我们就用一个例子来介绍如何将标签上的文本转换成黑底白字。
神奇像素科技
2021/12/23
1.7K0
如何将标签上的文本转换成黑底白字
Word里面处理图像若干
点击一张图片,看右上角的小方格.随便点击一个文字环绕里面的选项.变成非嵌入式的意思~
云深无际
2021/04/14
2810
Word里面处理图像若干
PS-前端切图教程(切jpg图和切png图)
ps:多日后的补充说明 部分看了文章的设计师,来找我说怎么切图。sorry?在我的理解,这就是切图啊,但是他们所指的“切图”是,怎么把设计图制作成html页面。 在我看来,现在人们对于前端都是有误区的。认为前端是切图的,(也确实是这么叫的,本人情感上很不愿意听前端被叫做“切图的”)所以也会误认为我的这篇文章是写给设计师的。 其实不然,这篇文章适用于计算机出身的前端甚至后端、对于ps等设计软件没有基础的人使用的,用来把设计师交于前端工程师的设计图稿或者psd源文件提取、整理,转化成布局页面时使用的图片。 再者
xing.org1^
2018/05/17
16.4K0
平面设计师必备的AI快捷键
在开多个AI文档的情况下。来回切换是有点麻烦的,点来点去有点慢 CTRL+F6,可以来回切换。
半夜喝可乐
2018/10/25
2.7K0
Axure RP8入门之基本操作篇
格式说明:“Password”表示主要用途;“Input”表示元件类型,一般情况下可省略,当有不同类型的同名元件需要区分或名称不能明确表达用途的时候使用;“01”表示出现多个同名元件时的编号;单词首字母大写的书写格式便于阅读。
胡琦
2021/09/09
5.7K0
相关推荐
利用Word制作简易版的电子签名
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验