终止线程的三种方法
1. 使用退出标志终止线程
package chapter2;
public class ThreadFlag extends
Thread
{
}
thread.stop();
package chapter2;
public class ThreadInterrupt extends
Thread
{
}
如何停止JAVA线程
如何停止java的线程一直是一个困恼我们开发多线程程序的一个问题。这个问题最终在Java5的java.util.concurrent中得到了回答:使用interrupt(),让线程在run方法中停止。
简介
在Java的多线程编程中,java.lang.Thread类型包含了一些列的方法start(),
在Sun公司的一篇文章《Why are
Thread.stop, Thread.suspend and Thread.resume
Deprecated?
建议使用的方法
在《Why are
Thread.stop, Thread.suspend and Thread.resume
Deprecated?
关于使用volatile关键字的原因,请查看http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#36930。
当线程处于非运行(Run)状态
当线程处于下面的状况时,属于非运行状态:
-
当sleep方法被调用。
-
当wait方法被调用。
-
当被I/O阻塞,可能是文件或者网络等等。
当线程处于上述的状态时,使用前面介绍的方法就不可用了。这个时候,我们可以使用interrupt()来打破阻塞的情况,如:
public void stop() { Thread tmpBlinker = blinker; blinker = null; if (tmpBlinker != null) { tmpBlinker.interrupt(); } }
当interrupt()被调用的时候,InterruptedException将被抛出,所以你可以再run方法中捕获这个异常,让线程安全退出:
try { .... wait(); } catch (InterruptedException iex) { throw new RuntimeException("Interrupted",iex); }
阻塞的I/O
当线程被I/O阻塞的时候,调用interrupt()的情况是依赖与实际运行的平台的。在Solaris和Linux平台上将会抛出InterruptedIOException的异常,但是Windows上面不会有这种异常。所以,我们处理这种问题不能依靠于平台的实现。如:
package com.cnblogs.gpcuster import java.net.*; import java.io.*; public abstract class InterruptibleReader extends Thread { private Object lock = new Object( ); private InputStream is; private boolean done; private int buflen; protected void processData(byte[] b, int n) { } class ReaderClass extends Thread { public void run( ) { byte[] b = new byte[buflen]; while (!done) { try { int n = is.read(b, 0, buflen); processData(b, n); } catch (IOException ioe) { done = true; } } synchronized(lock) { lock.notify( ); } } } public InterruptibleReader(InputStream is) { this(is, 512); } public InterruptibleReader(InputStream is, int len) { this.is = is; buflen = len; } public void run( ) { ReaderClass rc = new ReaderClass( ); synchronized(lock) { rc.start( ); while (!done) { try { lock.wait( ); } catch (InterruptedException ie) { done = true; rc.interrupt( ); try { is.close( ); } catch (IOException ioe) {} } } } } }
另外,我们也可以使用InterruptibleChannel接口。
实现了InterruptibleChannel接口的类可以在阻塞的时候抛出ClosedByInterruptExcepti
。如:
package com.cnblogs.gpcuster import java.io.BufferedReader; import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.channels.Channels; public class InterruptInput { static BufferedReader in = new BufferedReader( new InputStreamReader( Channels.newInputStream( (new FileInputStream(FileDescriptor.in)).getChannel()))); public static void main(String args[]) { try { System.out.println("Enter lines of input (user ctrl+Z Enter to terminate):"); System.out.println("(Input thread will be interrupted in 10 sec.)"); // interrupt input in 10 sec (new TimeOut()).start(); String line = null; while ((line = in.readLine()) != null) { System.out.println("Read line:'"+line+"'"); } } catch (Exception ex) { System.out.println(ex.toString()); // printStackTrace(); } } public static class TimeOut extends Thread { int sleepTime = 10000; Thread threadToInterrupt = null; public TimeOut() { // interrupt thread that creates this TimeOut. threadToInterrupt = Thread.currentThread(); setDaemon(true); } public void run() { try { sleep(10000); // wait 10 sec } catch(InterruptedException ex) {} threadToInterrupt.interrupt(); } } }
这里还需要注意一点,当线程处于写文件的状态时,调用interrupt()不会中断线程。
参考资料
How to Stop a Thread or a Task
Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?
不提倡的stop()方法
臭名昭著的stop()停止线程的方法已不提倡使用了,原因是什么呢?
当在一个线程对象上调用stop()方法时,这个线程对象所运行的线程就会立即停止,并抛出特殊的ThreadDeath()异常。这里的“立即”因为太“立即”了,
假如一个线程正在执行:
synchronized void { x = 3; y = 4; }
由于方法是同步的,多个线程访问时总能保证x,y被同时赋值,而如果一个线程正在执行到x = 3;时,被调用了 stop()方法,即使在同步块中,它也干脆地stop了,这样就产生了不完整的残废数据。而多线程编程中最最基础的条件要保证数据的完整性,所以请忘记 线程的stop方法,以后我们再也不要说“停止线程”了。
interupt()中断线程
- 正常运行.
- 处理结束前的工作,也就是准备结束.
- 结束退出.
while(!isInterrupted()){ 正常逻辑 }
,一个测试类,ThreadDemo
这样ThreadDemo调用interrupt()方法,isInterrupted()为true,就会退出运行。但是如果线程正在执行wait,sleep,join方法,你调用interrupt()方法,这个逻辑就不完全了。
我们可以这样处理:
public void run(){ while(!isInterrupted()){ try{ 正常工作 }catch(InterruptedException e){ //nothing } } } }想一想,如果一个正在sleep的线程,在调用interrupt后,会如何?wait方法检查到isInterrupted()为true,抛出异常, 而你又没有处理。而一个抛出了InterruptedException的线程的状态马上就会被置为非中断状态,如果catch语句没有处理异常,则下一 次循环中isInterrupted()为false,线程会继续执行,可能你N次抛出异常,也无法让线程停止。
这个错误情况的实例代码
ThreadA
public
}
}
那么如何能确保线程真正停止?在线程同步的时候我们有一个叫“二次惰性检测”(double check),能在提高效率的基础上又确保线程真正中同步控制中。那么我把线程正确退出的方法称为“双重安全退出”,即不以isInterrupted ()为循环条件。而以一个标记作为循环条件:
正确的ThreadA代码是:
public
}
1 处于运行状态的线程停止
-
private
volatile Thread blinker; -
public
void stop() { -
blinker = null; -
}
-
public
void run() { -
Thread thisThread = Thread.currentThread(); -
while (blinker == thisThread) { -
try { -
//业务流程 -
} catch (Exception e){} -
} -
}"font-size:12px;">
-
2 即将或正在处于非运行态的线程停止
可中断等待:线程调用了sleep或wait方法,这些方法可抛出InterruptedException;
Io阻塞:线程调用了IO的read操作或者socket的accept操作,处于阻塞状态。
2.1 处于可中断等待线程的停止
-
private
volatile Thread blinker; -
public
void stop() { -
Thread tmp = blinker; -
blinker = null; -
if(tmp!=null){ -
tmp.interrupt(); -
} -
}
-
public
void run() { -
while (!Thread.currentThread().isInterrupted()) { -
try { -
//业务流程 -
} catch (Exception e){} -
} -
}
2.2 处于IO阻塞状态线程的停止
-
new
InputStreamReader( -
Channels.newInputStream( -
(new FileInputStream(FileDescriptor.in)).getChannel())));
3 处于大数据IO读写中的线程停止
4 在线程运行前停止线程
-
public
void run() { -
if (myThread null)== { -
return; // stopped before started. -
} -
while(!Thread.currentThread().isInterrupted()){ -
//业务逻辑 -
} -
}