论述题 5.  Java语言中有几种方法可以终止线程运行?stop()和suspend()方法为什么不推荐使用?
【正确答案】在Java语言中,可以使用stop方法与suspend方法来终止线程的执行。当使用Thread.stop()方法来终止线程时,它会释放已经锁定的所有的监视资源。如果当前任何一个受这些监视资源保护的对象处于一个不一致的状态,其他的线程将会看到这个不一致的状态,这可能会导致程序执行的不确定性,并且这种问题很难被定位。suspend方法的使用容易引起死锁。由于调用suspend方法不会释放锁,这就会导致一个问题:如果使用一个suspend挂起一个有锁的线程,那么在锁恢复之前将不会被释放。如果调用suspend方法的线程试图取得相同的锁,程序就会发生死锁。例如,线程A已经获取到了互斥资源M的锁,然后调用suspend方法挂起了A的执行,如果没有线程唤醒线程A且线程B也去访问互斥资源,此时线程B就会出现冻结无法执行下去了,也可以理解为出现了死锁。鉴于以上两种方法的不安全性,Java语言已经不建议使用以上两种方法来终止线程。
   那么,如何才能终止线程呢?一般建议采用的方法是让线程自行结束,进入Dead(死亡)状态。一个线程要进入Dead状态,就是执行完run方法,也就是说,如果想要停止一个线程的执行,就要提供某种方式让线程能够自动结束run方法的执行。在实现的时候,可以通过设置一个flag标志来控制循环是否执行,通过这种方法来让线程离开run方法,从而终止线程。下例给出了结束线程的方法。
   public class MyThread implements Runnable
   {
   private volaile Boolean flag;
   public void stop()
   {
   flag=false;
   }
   public void run()
   {
   while(flag)
   ;//do something
   }
   }
   上例中,通过调用MyThread的stop方法虽然能够终止线程,但同样也存在问题:当线程处于非运行状态时(当sleep方法被调用或当wait方法被调用或当被I/O阻塞),上面介绍的方法就不可用了。此时可以使用interrupt方法来打破阻塞的情况,当interrupt被调用的时候,会抛出InterruptedException异常,可以通过在run方法中捕获这个异常来让线程安全退出,具体实现方式如下:
   public class Mylbread
   {
   public static void main(String[]args)
   {
   Thread thread=new Thread(new Runnable()
   {
   public void run()
   {
   System.out.println("thread go to sleep");
   try
   {
   //用休眠来模拟线程被阻塞
   Tbread.sleep(5000);
   System.out.println("thread finish");
   }
   catch(InterruptedException e)
   {
   System.out.println("thread is imerupted!");
   }
   }
   });
   thread.start();
   thread.intermpt();
   }
   程序的运行结果为:
   thread go to sleep
   thread is interupted!
   如果程序因为I/O而停滞,进入非运行状态,基本上要等到I/O完成才能离开这个状态,在这种情况下,无法使用interrupt来使程序离开run方法。需要使用一个替代的方法,其基本思路也是触发一个异常,而这个异常与所使用的I/O相关,例如,如果使用readLine方法(readLine方法是BufferedReader中一个非常常用的方法,使用它可以从一段输入流中一行一行地读数据,行的区分用“\r”“\n”或者“\r\n”)在等待网络上的一个信息,此时线程处于阻塞状态。让程序离开run的方法就是使用close方法来关闭流,在这种情况下会引发IOException异常,run方法可以通过捕获这个异常来安全结束线程。
【答案解析】