疯狂java


您现在的位置: 疯狂软件 >> 新闻资讯 >> 正文

如何停止一个Java线程


 

   

  Java推荐的标准方法:使用interrupt终止线程

  如何使用interrupt中断一个线程?通常的做法是在线程外部调用interrupt方法,线程内部会接收到相应异常,然后在异常处理中安全退出线程。请看下面的例子:

  public class MyThread implements Runnable

  {

  private Thread runner = new Thread(this, "runner");

  public void start()

  {

  runner.start();

  }

  public void interrupt()

  {

  runner.interrupt();

  }

  @Override

  public void run()

  {

  while(true)

  {

  try

  {

  Thread.sleep(1000);

  System.out.println("thread is running.");

  }

  catch(Exception e)

  {

  System.out.println("thread exit.");

  break;

  }

  }

  }

  public static void main(String[] args)

  {

  MyThread myThread = new MyThread();

  try

  {

  myThread.start();

  Thread.sleep(5000);

  myThread.interrupt();

  }

  catch(Exception e)

  {

  System.out.println(e);

  }

  }

  }

  那么,是否调用interrupt方法,线程内部都会收到响应异常?其实不是这样,如果线程内部没有调用sleep/wait/join等方法,线程是不会接收到响应异常的。请看看下面的例子。

  public class MyThread implements Runnable

  {

  private Thread runner = new Thread(this, "runner");

  public void start()

  {

  runner.start();

  }

  public void interrupt()

  {

  runner.interrupt();

  }

  @Override

  public void run()

  {

  try

  {

  while(true)

  {

  int a = 1;

  }

  }

  catch(Exception e)

  {

  System.out.println(e);

  }

  }

  public static void main(String[] args)

  {

  MyThread myThread = new MyThread();

  try

  {

  myThread.start();

  Thread.sleep(5000);

  myThread.interrupt();

  }

  catch(Exception e)

  {

  System.out.println(e);

  }

  }

  }

  参考JDK文档可知,调用interrupt终止线程可分为以下几种情况:

  a> 如果线程被阻塞在wait/sleep/join等方法调用,调用interrupt方法,线程内部会接受到InterruptedException

  b> 如果线程被阻塞在基于interruptible channel实现的I/O操作,调用interrrupt方法,通道会被关闭,线程内部会接收到ClosedByInterruptException.

  c> 如果线程被阻塞在Selector,selection操作会立刻返回,且返回值非负。

  d> 除了上述情况,其他情况Interrupt只会简单是设置中断标识位。

  从上面描述可知,这里需要解决两个问题:

  对于没有阻塞的方法,使用interrupt如何终止线程;

  对于没有基于interruptible channel实现的I/O操作,如果终止线程。

  看第一个问题:终止没有阻塞的线程。

  对于这类线程,调用interrupt,线程内部不会受到相应异常,只是设置了中断标识,这时候可以通过检测中断标识位,判断是否终止线程。

  public class MyThread implements Runnable

  {

  private Thread runner = new Thread(this, "runner");

  public void start()

  {

  runner.start();

  }

  public void interrupt()

  {

  runner.interrupt();

  }

  @Override

  public void run()

  {

  while(true)

  {

  if(runner.isInterrupted())

  {

  System.out.println("thread exit.");

  break;

  }

  }

  }

  public static void main(String[] args)

  {

  MyThread myThread = new MyThread();

  try

  {

  myThread.start();

  Thread.sleep(5000);

  myThread.interrupt();

  }

  catch(Exception e)

  {

  System.out.println(e);

  }

  }

  }

  第二个问题:终止没有基于interruptible channel实现的I/O操作。这时候Interrupt方法就无能为力,可以尝试使用Thread.stop,关于stop的使用下面详细讨论

  使用stop方法终止线程

  Stop方法现在已经不推荐使用了。详见Java的官方文档,对于不建议使用stop等方法的说明:

  主要原因是,使用stop后,线程会立即是否所持有的锁。使用锁的本意通常是为了同步,保证数据的一致性。

  另外,使用stop,线程会受到ThreadDeath的异常,而且这个异常可能发生在任何时候,包括catch和finally。

  那么使用stop是否可以终止任何线程?其实不是这样,stop是一个同步方法,需要获取到对象锁,如果要终止的线程已占用的了锁,且不释放,stop方法一样也无法终止。