中断Java线程

来源:互联网 发布:大数据的网络资源 编辑:程序博客网 时间:2024/06/06 06:40

中断一个线程意味着还未完成线程的任务之前结束该线程,有效地终止当前的操作。该线程是否死亡、或等待新的任务,或执行下一步依赖于当前应用。
首先,不要使用Thread.stop()方法。它确实能终止一个运行的线程,但是这个方法是不安全的并且是过期的(deprecated),意味着在未来的java版本中不可用。
另一个方法令人困惑的方法Thread.interrupt(),但是该方法不能终止一个运行的线程,如:

class Example1 extends Thread {  public static void main( String args[] ) throws Exception {   Example1 thread = new Example1();   System.out.println( "Starting thread..." );   thread.start();   Thread.sleep( 3000 );   System.out.println( "Interrupting thread..." );   thread.interrupt();   Thread.sleep( 3000 );   System.out.println( "Stopping application..." );   System.exit( 0 );  }  public void run() {    while ( true ) {     System.out.println( "Thread is running..." );      long time = System.currentTimeMillis();      while ( System.currentTimeMillis()-time < 1000 ) {      }    }  }}

输出

Starting thread...Thread is running...Thread is running...Thread is running...Interrupting thread...Thread is running...Thread is running...Thread is running...Stopping application...

上面的代码创建了一个线程并使用Thread.interrupt()终止该线程,调用Thread.sleep()方法给线程足够的时间初始化和终止,线程本身并未做其他事情。尽管调用了Thread.interrupt()方法,但是线程还是运行了一会。

最好的并且推荐使用一个共享变量终止线程,该共享变量用来通知线程必须终止当前所做的任务。该线程周期性地检查该变量,特别是在冗长的操作期间,有序地终止当前的任务。代码如下:

class Example2 extends Thread {  volatile boolean stop = false;  public static void main( String args[] ) throws Exception {   Example2 thread = new Example2();   System.out.println( "Starting thread..." );   thread.start();   Thread.sleep(3000);   System.out.println( "Asking thread to stop..." );   thread.stop = true;   Thread.sleep(3000);   System.out.println( "Stopping application..." );   System.exit(0);  }  public void run() {    while (!stop) {     System.out.println( "Thread is running..." );      long time = System.currentTimeMillis();      while ( (System.currentTimeMillis()-time < 1000) && (!stop) ) {      }    }   System.out.println( "Thread exiting under request..." );  }}

输出:

Starting thread...Thread is running...Thread is running...Thread is running...Asking thread to stop...Thread exiting under request...Stopping application...

尽管上面的方法需要一些额外的代码,但是它不难实现,并且给线程进行必要清理的机会,能够完全满足多线程应用的要求。只需要声明一个volatile的共享变量,然后将它封装在同步代码块或者方法中。

但是,如果线程由于等待某个事件被阻塞,阻塞的线程是无法检查共享变量,终止自己。这些场景会经常遇到,如Object.wait(),ServerSocket.accept()和 DatagramSocket.receive()等等。这些方法会一直阻塞线程,尽管使用超时机制,等待时间过期并不可行,所以必须使用提前退出阻塞状态的机制。
在Example1中,Thread.interrupt()方法并没有中断运行的线程,当线程处于阻塞状态,该方法会抛出中断异常,线程会退出阻塞状态。具体来讲,当线程被阻塞在Object.wait,Thread.join,或者Thread.sleep时,线程会接受InterruptedException1,提前终止阻塞的方法。
所以,如果一个线程被上面的方法阻塞,正确结束它的方式是设置共享变量,并调用interrupt()方法(注意,先设置共享变量)。如果线程没有被阻塞,调用interrupt()方法不会破坏线程,否则,线程会得到一个异常,并跳出当前阻塞的状态。无论哪种情形,线程最终会测试共享变量停止。

class Example3 extends Thread {  volatile boolean stop = false;  public static void main( String args[] ) throws Exception {   Example3 thread = new Example3();   System.out.println( "Starting thread..." );   thread.start();   Thread.sleep( 3000 );   System.out.println( "Asking thread to stop..." );   thread.stop = true;   thread.interrupt();   Thread.sleep( 3000 );   System.out.println( "Stopping application..." );   System.exit( 0 );  }  public void run() {    while (!stop ) {     System.out.println( "Thread running..." );      try {      Thread.sleep( 1000 );      } catch ( InterruptedException e ) {      System.out.println( "Thread interrupted..." );      }    }   System.out.println( "Thread exiting under request..." );  }}

输出:

Starting thread...Thread running...Thread running...Thread running...Asking thread to stop...Thread interrupted...Thread exiting under request...Stopping application...

如果线程碰到阻塞的I/O操作,I/O操作会阻塞一个线程相当多的时间,特别是网络通信的参与。这时候Thread.interrupt()方法不会让线程退出阻塞状态。代码如下:

class Example4 extends Thread {  public static void main( String args[] ) throws Exception {   Example4 thread = new Example4();   System.out.println( "Starting thread..." );   thread.start();   Thread.sleep( 3000 );   System.out.println( "Interrupting thread..." );   thread.interrupt();   Thread.sleep( 3000 );   System.out.println( "Stopping application..." );   System.exit( 0 );  }  public void run() {   ServerSocket socket;    try {      socket = new ServerSocket(7856);    } catch ( IOException e ) {     System.out.println( "Could not create the socket..." );      return;    }    while ( true ) {     System.out.println( "Waiting for connection..." );      try {       Socket sock = socket.accept();      } catch ( IOException e ) {      System.out.println( "accept() failed or interrupted..." );      }    }  }}

尽管调用了interrupt()方法,但是线程不会退出阻塞状态。
不过java平台提供了一种技术——调用socket的close()方法。在这种情形下,如果线程被I/O操作阻塞,会收到SocketException异常,类似于InterruptedException。唯一需要注意的是socket应用可用,即socket对象是共享的

import java.net.*;import java.io.*;class Example5 extends Thread {  volatile boolean stop = false;  volatile ServerSocket socket;  public static void main( String args[] ) throws Exception {    Example5 thread = new Example5();   System.out.println( "Starting thread..." );   thread.start();   Thread.sleep( 3000 );   System.out.println( "Asking thread to stop..." );   thread.stop = true;   thread.socket.close();   Thread.sleep( 3000 );   System.out.println( "Stopping application..." );   System.exit( 0 );  }  public void run() {    try {      socket = new ServerSocket(7856);    } catch ( IOException e ) {     System.out.println( "Could not create the socket..." );      return;    }    while ( !stop ) {     System.out.println( "Waiting for connection..." );      try {       Socket sock = socket.accept();      } catch ( IOException e ) {      System.out.println( "accept() failed or interrupted..." );      }    }   System.out.println( "Thread exiting under request..." );  }}

输出:

Starting thread...Waiting for connection...Asking thread to stop...accept() failed or interrupted...Thread exiting under request...Stopping application...

参考资料:
1. Adding Multithreading Capability to Your Java Applications
2. InterruptedException and interrupting threads explained


  1. InterruptedException的处理方式:
    - 吞并异常。只要你能确定InterruptedException不会再出现(Are you sure? Really?);
    - 设置中断标识位。这是你的代码不知道该怎么处理它,但是线程还在做其他的事情,该线程同样也会对InterruptedException感兴趣,Thread.currentThread().interrupt()
    - 传递异常。这是你的方法不知道该怎么处理,也许调用知道,这是最好的处理方式;
    - 处理异常。也许当前的线程想停止,当接收到InterruptedException。
    - 封装成其他异常。 ↩
1 0
原创粉丝点击