什么是中断?
在 Java 中没有办法立即停止一个线程,然而停止线程却显得尤为重要,如提前终止一个比较耗时的操作。因此,Java 提供了一种用于停止线程的机制 - 中断。
中断只是一种协作机制,Java 没有给中断增加任何语法,中断的过程完全需要程序员自己实现。若要中断一个线程,你需要手动调用该线程的 interrupt 方法,该方法也仅仅是将线程对象的中断标识设成true;接着你可以调用 interrupted 方法检测当前线程的标识位;如果为true,表示别的线程要求这条线程中断,此时究竟该做什么需要你自己写代码实现。
每个线程对象中都有一个标识,用于表示线程是否被中断;该标识位为 true 表示中断,为 false 表示未中断;
通过调用线程对象的 interrupt 方法将该线程的标识位设为 true ;可以在别的线程中调用,也可以在自己的线程中调用。
另外,一个线程不应该由其他线程来强制中断或停止,而是应该由线程自己自行停止。所以,Thread.stop, Thread.suspend, Thread.resume 都已经被废弃了。而 Thread.interrupt 的作用其实也不是中断线程,而是「通知线程应该中断了」,具体到底中断还是继续运行,应该由被通知的线程自己处理。
案例
public class Main {public static void main(String[] args) {Ticket ticket = new Ticket();TicketingWindow window1 = new TicketingWindow(ticket);TicketingWindow window2 = new TicketingWindow(ticket);TicketingWindow window3 = new TicketingWindow(ticket);window1.setName("1号售票窗口");window2.setName("2号售票窗口");window3.setName("3号售票窗口");window1.start();window2.start();window3.start();// 告知窗口 2 可以停止售票了window2.interrupt();try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}window1.StopSelling();}}class Ticket {public int stock = 5;}class TicketingWindow extends Thread {public TicketingWindow(Ticket ticket) {this.ticket = ticket;}private Ticket ticket;private boolean status = true;@Overridepublic void run() {while (ticket.stock > 0 && status) {try {// 每隔 20 秒卖出一张票System.out.println(this.getName() + "休眠中...");sleep(2000);} catch (InterruptedException e) {System.out.println(this.getName() + "提前停止服务");return;}System.out.println(this.getName() + ":" + --ticket.stock);}System.out.println(this.getName() + "停止服务");}public void StopSelling() {System.out.println(this.getName() + "即将提前停止服务");this.status = false;}}
补充
具体来说,当对一个线程,调用 interrupt() 时,
① 如果线程处于被阻塞状态(例如处于sleep, wait, join 等状态),那么线程将立即退出被阻塞状态,并抛出一个InterruptedException异常。仅此而已。
② 如果线程处于正常活动状态,那么会将该线程的中断标志设置为 true,仅此而已。被设置中断标志的线程将继续正常运行,不受影响。
interrupt() 并不能真正的中断线程,需要被调用的线程自己进行配合才行。也就是说,一个线程如果有被中断的需求,那么就可以这样做。
① 在正常运行任务时,经常检查本线程的中断标志位,如果被设置了中断标志就自行停止线程。
② 在调用阻塞方法时正确处理InterruptedException异常。(例如,catch异常后就结束线程。)
Thread thread = new Thread(() -> {while (!Thread.interrupted()) {// do more work.}});thread.start();// 一段时间以后thread.interrupt();
