当前位置: 首页 > 后端技术 > Java

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

时间:2023-04-01 17:36:05 Java

Java中有两种锁,一种是内置锁synchronized,一种是显示锁Lock,其中Lock锁是可中断锁,而synchronized锁是不可中断锁。所谓中断锁,是指锁在执行过程中可以被打断,也就是在执行过程中可以收到中断通知,从而打断锁的执行。PS:Lock默认也是不可中断锁,但是可以通过特殊的“手段”变成可中断锁。接下来我们一起来看看吧。为什么我们需要可中断锁?不间断锁的问题在于,当出现“异常”时,只能阻塞等待,没有别的办法,比如下面的程序。下面程序中有两个线程,其中线程1首先获取锁资源执行相应的代码,线程2在0.5s后开始尝试获取锁资源,但是线程1在执行时忘记释放锁,从而导致线程2阻塞等待的情况,实现代码如下:String[]args){锁lock=newReentrantLock();//创建线程1Threadt1=newThread(newRunnable(){@Overridepublicvoidrun(){lock.lock();System.out.println("Thread1:acquiredthelock.");//Thread1还没有释放锁}});t1.开始();//创建线程2Threadt2=newThread(newRunnable(){@Overridepublicvoidrun(){//先休眠0.5s,让线程1先执行try{Thread.sleep(500);}catch(InterruptedExceptione){e.printStackTrace();}//获取锁System.out.println("Thread2:waitingtogetthelock.");lock.lock();try{System.out.println("线程2:成功获取锁。");}finally{lock.unlock();}}});t2.start();}}上面代码执行的结果如下:从上面的结果可以看出,线程2此时正在等待获取锁的操作,但是过了Nlongtime...再次查看结果,还是熟悉的画面:线程2还在阻塞等待获取线程1释放锁资源,此时线程2除了等待没有别的办法,而且当我们巧妙的取出JConsole试图获取具体死锁信息,我们得到这样的结果:没有检测到死锁信息。从上图可以看出,当只有一个锁资源时,系统不会判断这种情况为死锁。当然,有没有关于阻塞和等待的具体信息。此时只有线程2独自等待它的“锁”。使用中断锁,但是中断锁的出现可以打破这个死锁。它可以在等待一定时间后主动中断线程2,解决线程阻塞等待的问题。中断锁的核心实现代码是lock.lockInterruptibly()方法,与lock.lock()方法类似,只是可以先使用lockInterruptibly方法接收中断请求。中断锁的具体实现如下:importjava.util。concurrent.locks.Lock;导入java.util.concurrent.locks.ReentrantLock;公共类InterruptiblyExample{publicstaticvoidmain(String[]args)throwsInterruptedException{Locklock=newReentrantLock();//创建线程1Threadt1=newThread(newRunnable(){@Overridepublicvoidrun(){try{//加锁操作lock.lock();System.out.println("线程1:获得了锁。");}catch(InterruptedExceptione){e.printStackTrace();}//线程1还没有释放锁}});t1.开始();//创建线程2Threadt2=newThread(newRunnable(){@Overridepublicvoidrun(){//先休眠0.5s,让线程1先执行try{线程.睡眠(500);}catch(InterruptedExceptione){e.printStackTrace();}//获取锁try{System.out.println("Thread2:trytogetalock.");锁.lockInterruptibly();//可中断锁System.out.println("Thread2:Successfullyacquiredlock.");}catch(InterruptedExceptione){System.out.println("线程2:执行已被中断。");}}});t2.开始();//等待2s后,终止线程2Thread.sleep(2000);if(t2.isAlive()){//线程2仍在执行System.out.println("executionthreadInterrupt.");t2.中断();}else{System.out.println("线程2:执行完成。");}}}上面的代码执行结果如下:从上面的结果可以看出,当我们使用lockInterruptibly方法时,可以判断一段时间后是否仍然阻塞等待。如果结果为真,可以直接中断,如上图效果所示但是当我们尝试将lockInterruptibly方法替换为lock方法时(其他代码不变),执行结果就完全不同了。实现代码如下:importjava.util.concurrent.locks.Lock;importjava.util。concurrent.locks.ReentrantLock;公共类InterruptiblyExample{publicstaticvoidmain(String[]args)throwsInterruptedException{Locklock=newReentrantLock();//创建线程1Threadt1=newThread(newRunnable(){@Overridepublicvoidrun(){try{//加锁操作lock.lockInterruptibly();System.out.println("线程1:获得了锁。");}catch(InterruptedExceptione){e.printStackTrace();}//线程1没有释放锁}});t1.开始();//创建线程2Threadt2=newThread(newRunnable(){@Overridepublicvoidrun(){//先休眠0.5s,让线程1先执行try{Thread.sleep(500);}catch(InterruptedExceptione){e.printStackTrace();}//获取锁try{System.out.println("Thread2:trytogetalock.");锁.锁();System.out.println("线程2:成功获取锁。");}catch(Exceptione){System.out.println("线程2:执行已被中断。");}}});t2.开始();//等待2s之后,终止线程2Thread.sleep(2000);if(t2.isAlive()){//线程2仍在执行System.out.println("Executionthreadinterrupt.");t2.中断();}else{System.out.println("线程2:执行完成。");}}}上面程序的执行结果如下:从上图可以看出,当使用lock方法时,即使调用了中断方法,线程2仍然无法被中断总结本文介绍的中断锁的实现,通过显示锁Lock的lockInterruptibly方法完成。和lock方法类似,但是lockInterruptibly可以先收到中断通知,而lock方法只能“死等”锁资源Release,这两种方法的区别也是面试常见问题,希望这篇文章对你有用。4种方法创建和使用并发原创文章推荐帖详解!Java中的用户线程和守护线程有这么大的区别吗?深入理解ThreadPool线程池的7种创建方式,强烈推荐大家使用……池化技术到底有多牛?看到线程和线程池的对比,惊呆了!并发中的线程同步和locksynchronized锁this和class的区别!volatile和synchronized的区别轻量级锁就一定比重量级锁快吗?这样终止线程会导致服务宕机?SimpleDateFormat线程不安全的5个解决方案!ThreadLocal不好用?这就是你没用的原因!ThreadLocal内存溢出代码演示及原因分析!信号量告白:限流器我用对了!CountDownLatch:别招手了,等大家再次加入我们!CyclicBarrier:当所有人都准备好后,司机就可以发动汽车了!synchronized优化方法的锁扩展机制!synchronized中的4个优化,你知道几个?ReentrantLock的4个坑!图解:为什么非公平锁性能更高?4个解决死锁的工具!死锁终结者:顺序锁和轮询锁!使用轮询锁遇到的问题及解决方法!关注公众号“Java中文社区”,查看更多有趣的Java并发知识文章。

最新推荐
猜你喜欢