中断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
- InterruptedException的处理方式:
- 吞并异常。只要你能确定InterruptedException不会再出现(Are you sure? Really?);
- 设置中断标识位。这是你的代码不知道该怎么处理它,但是线程还在做其他的事情,该线程同样也会对InterruptedException感兴趣,Thread.currentThread().interrupt()
;
- 传递异常。这是你的方法不知道该怎么处理,也许调用知道,这是最好的处理方式;
- 处理异常。也许当前的线程想停止,当接收到InterruptedException。
- 封装成其他异常。 ↩
- Java线程:线程中断
- Java线程中断机制-如何中断线程
- 中断JAVA线程
- 中断JAVA线程
- 中断Java线程
- 中断JAVA线程
- 正确中断java线程
- 中断JAVA线程
- Java 可中断线程
- 中断Java线程
- Java 线程中断
- java线程中断
- Java线程中断
- 如何中断JAVA线程
- JAVA线程中断
- Java线程中断
- java 可中断线程
- Java中的线程中断
- 我的博客开始
- 矩阵的tr
- 双11引发的思考
- Android UsageStatsService源码
- Android Studio导入Eclipse工程及相关问题
- 中断Java线程
- Android基础入门教程——10.11 传感器专题(2)——方向传感器
- 推送
- hdoj 5500 Reorder the Books 【规律】
- webSocket协议
- 论java底层native
- CC2541 AirSync(4)——封包、解包
- object-c 初次接触
- 公共 DNS 服务器 IP 地址