中断Java线程

中断一个线程意味着还未完成线程的任务之前结束该线程,有效地终止当前的操作。该线程是否死亡、或等待新的任务,或执行下一步依赖于当前应用。
首先,不要使用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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值