1.3 线程中断

一个多线程Java程序,只有当其全部线程执行结束时(更具体地说,是所有非守护线程结束或者某个线程调用System.exit()方法的时候),才会结束运行。有时,为了终止程序或者取消一个线程对象所执行的任务,我们需要终止一个线程。

Java使用一种中断机制来向线程表明想要终止它。这个中断机制依靠线程对象来检查是否需要中断,同时线程对象可以决定是否响应中断请求。当然,一个线程对象也可以忽略中断请求继续执行。

本节将开发一个应用程序,它的作用是在线程创建5s后,使用中断机制强制结束线程。

项目准备

本案例是用Eclipse IDE来实现的。如果开发者使用Eclipse或者其他IDE(例如NetBeans),则应打开它并创建一个新的Java项目。

案例实现

根据以下步骤来完成本案例。

1.创建一个名为PrimeGenerator的类,并继承Thread类:

        public class PrimeGenerator extends Thread{

2.重写run()方法——该方法包含一个无限while循环。在循环中,处理从1开始的连续数字。如果是奇数,那么将其输出到控制台:

        @Override
        public void run() {
          long number=1L;
          while (true) {
            if (isPrime(number)) {
              System.out.printf("Number %d is Prime\n",number);
            }

3.每处理完一个数字,通过isInterrupted()方法来判断当前线程是否已被中断。如果该方法返回true,那么表明当前线程已被中断。在这种情况下,在控制台上打印一条信息并终止线程:

            if (isInterrupted()) {
              System.out.printf("The Prime Generator has been Interrupted");
              return;
            }
            number++;
          }
        }

4.实现isPrime()方法。详细代码参见1.2节。

5.现在,开始实现应用程序的主类,创建包含main()方法的Main类:

        public class Main {
          public static void main(String[] args) {

6.创建PrimeGenerator类的对象,并启动它:

        Thread task=new PrimeGenerator();
        task.start();

7.在主线程中等待5s后,中断PrimeGenerator线程:

        try {
          Thread.sleep(5000);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
        task.interrupt();

8.输出中断线程的状态。这段代码的输出结果取决于它是在线程结束前还是线程结束后运行的:

        System.out.printf("Main: Status of the Thread: %s\n",task.getState());
        System.out.printf("Main: isInterrupted: %s\n",task.isInterrupted());
        System.out.printf("Main: isAlive: %s\n", task.isAlive());
        }

9.运行案例并查看结果。

结果分析

下面是以上案例运行结果的截图。从图中可以看到,PrimeGenerator线程在检测到自己被中断后,输出信息并结束了运行。

Thread类有一个用来保存线程是否已被中断的状态属性,其属性值为boolean类型,默认值为false。当调用一个线程对象的interrupt()方法时,该状态属性将修改为true。而方法isInterrupted()仅返回该状态属性的值。

在main()方法中,输出了中断线程的一些状态信息。在本案例中,虽然在这些代码之前调用了线程的中断,但是在执行这些代码时,任务线程并未执行到中断判断和处理过程,因此,此时输出的线程状态为RUNNABLE,方法isInterrupted()的结果为true,当然方法isAlive()的结果也为true。如果这些代码执行是在Thread中断完成之后[可以制造机会,如通过在main调用sleep()使得主线程休眠1s,使得task线程完成中断,那么isInterrupted()和isAlive()的结果将为false。

其他说明

在Thread类中,还有一个静态方法interrupted(),也能用来检测当前线程是否已被中断。

注意:

isInterrupted()方法和interrupted()方法之间有一个重要的不同点:isInterrupted()方法不会修改线程的是否中断属性,而interrupted()方法会将中断属性设置为false。

正如前文所说,线程对象可以忽略中断,但这并不是被预期的行为。