时间:2021-05-19
大家肯定都使用过 Java 线程开发(Thread / Runnable),启动一个线程的做法通常是:
new Thread(new Runnable( @Override public void run() { // todo sth... })).start();然而线程退出,大家是如何做的呢?一般做法可能不外乎以下两种:
可能还会有人提出,我可以用中断来退出线程! 我只能说:Too Young Too Simple!中断并不会使得线程结束而退出,中断(interrupt)只是唤醒被阻塞的线程而已。
本篇,我们就来好好的聊聊:线程中断,以及如何正确的使用线程中断,和正确的线程退出。
以上是官方 JDK 中的源码注释说明,其含义如下:
**Thread.stop 方法天生就不安全。**使用该方法来停止线程,将会导致其它因为监视器锁『监视器我们在 synchronized 中就讲过,是 Java 的内置锁』而被锁住的线程全部都解锁!(本质的后果是:没有检查的 ThreadDeath 异常会在栈中传播,因而使得监视器锁解锁)。如果任何一个被监视器锁给锁住的对象处于一个不一致的状态,那么其被解锁后将会被其它线程可见,潜在的结果是产生任何后果。**我们应该使用一个变量来代替使用 stop 方法,告诉目标线程退出『这里就是我们开头所说的第一种方法,设置一个标志位』。**目标线程应该周期性的检查这个变量,并根据这个变量来正确的退出 run 方法。如果目标线程处于阻塞/休眠状态(如:使用 wait、sleep、yield 方法后,线程让出了 CPU 使用权,进而阻塞/休眠),此时,该标志位变量将不会起作用,那么,应该使用 interrupt 方法来中断目标线程的阻塞/休眠状态,将其唤醒!
对于 ThreadDeath 对象,官方还有补充:
所以,我们也别想着去 try-catch ThreadDeath Exception!
同样,被废弃的还有 Thread.resume 和 Thread.suspend。这俩方法有造成死锁的危险:
取代这两方法的正确方式是:Object.wait 和 Object.notify :
因为 Object.wait 进入阻塞时,会释放锁。
Thread 中有三个与中断相关的方法:
注:如果线程中断后,连续两次调用 Thread.interrupted(),第一次是 true & 清除状态,第二次结果是 false。
我们先来通过一个例子来初步了解 thread.interrupt :
public class InterruptDemo implements Runnable { @Override public void run() { while (true) { System.out.println("Thread running..."); } } public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(new InterruptDemo(), "InterruptDemo"); System.out.println("start thread"); thread.start(); Thread.sleep(50); System.out.println("interrupt thread"); thread.interrupt(); Thread.sleep(50); System.out.println("thread's status = " + thread.isInterrupted()); }}输出结果:
start threadThread running...Thread running.........interrupt threadThread running...Thread running.........thread's status = trueThread running.........我们可以看到,即便我们调用了 thread.interrupt 方法,线程也并没有退出,仍旧继续运行。因此,这个例子证明了一点:我们并不能通过"我们所认为的"中断来试图"结束"正在运行的线程。
同样,我们再来看一个例子:
public class InterruptDemo implements Runnable { @Override public void run() { while (true) { System.out.println("Thread will sleep 10s ------------------------- running"); long timestamp = System.currentTimeMillis(); try { Thread.sleep(10000); } catch (InterruptedException e) { System.out.println("thread interrupted..."); } timestamp = System.currentTimeMillis() - timestamp; System.out.println("Thread run, total sleep = " + timestamp + "(ms)"); } } public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(new InterruptDemo(), "InterruptDemo"); System.out.println("start thread"); thread.start(); Thread.sleep(3000); System.out.println("interrupt thread"); thread.interrupt(); System.out.println("main exit"); }}输出结果:
start threadThread will sleep 10s ------------------------- runninginterrupt threadmain exitthread interrupted...Thread run, total sleep = 3002(ms)Thread will sleep 10s ------------------------- runningThread run, total sleep = 10002(ms)Thread will sleep 10s ------------------------- running我们可以看到,线程启动后,进入睡眠(10s),3秒后被中断唤醒,执行完一个 while 后再次进入第二次睡眠(10s),然后周而复始。
输出结果:
start thread.......Thread run, total sleep = 0(ms)interrupt threadThread run, total sleep = 0(ms)Thread run, total sleep = 0(ms)Thread run, total sleep = 0(ms)main exitThread exit我们通过使用一个 AtomicBoolean 变量来当作标志位,使得我们的线程能正常退出。 我们也可以判断线程是否被中断而选择性的退出。
输出结果:
start thread.......Thread run, total sleep = 0(ms)interrupt threadThread run, total sleep = 0(ms)Thread run, total sleep = 0(ms)Thread run, total sleep = 0(ms)main exitThread exit输出结果:
start threadThread will sleep 10s ------------------------- runninginterrupt threadmain exitInterrupted... Todo other things then exit......Thread exit本文我们分析了线程的中断,并让大家了解了中断的含义:只是告诉该线程,你被『中断』了,至于你想干嘛,还是由你自己来决定。同时,我们也简单分析了几个废弃的方法的原因。希望大家学习了本文之后,能正确且合理的设计,线程如何安全的退出。
以上就是详解Java 线程中断的详细内容,更多关于Java 线程中断的资料请关注其它相关文章!
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
下面的这断代码大家应该再熟悉不过了,线程休眠需要捕获或者抛出线程中断异常,也就是你在睡觉的时候突然有个人冲进来把你吵醒了。try{Thread.sleep(30
Java如何实现线程中断?通过调用Thread类的实例方法interrupt。如下:Threadthread=newThread(){@Overridepubl
本文承接上一篇文章《Java多线程实例详解(一)》。四.Java多线程的阻塞状态与线程控制上文已经提到Java阻塞的几种具体类型。下面分别看下引起Java线程阻
详解Java中多线程异常捕获Runnable的实现1、背景:Java多线程异常不向主线程抛,自己处理,外部捕获不了异常。所以要实现主线程对子线程异常的捕获。2、
Java中CountDownLatch进行多线程同步详解CountDownLatch介绍在前面的Java学习笔记中,总结了Java中进行多线程同步的几个方法:1