Java 多線程編程中,java.lang.Thread 類包含 start()、stop()、stop(Throwable)、suspend()、destroy()、resume() 等方法。通過這些方法可方便操作線程,但只有 start() 方法被保留,其餘均被棄用。
Sun 文章《Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?》詳細講解棄用原因。那麼,究竟應如何停止線程?
文中建議使用如下方法停止線程:
private volatile Thread blinker;
public void stop() {
blinker = null;
}
public void run() {
Thread thisThread = Thread.currentThread();
while (blinker == thisThread) {
try {
thisThread.sleep(interval);
} catch (InterruptedException e) {}
repaint();
}
}
關於使用 volatile 關鍵字原因,請查看 Java 語言規範。
線程處於以下狀況屬非運行狀態:
sleep 方法wait 方法此時前面方法不可用。可用 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 阻塞時,調用 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 接口。實現此接口的類可在阻塞時拋出 ClosedByInterruptException。示例:
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.)");
(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());
}
}
public static class TimeOut extends Thread {
int sleepTime = 10000;
Thread threadToInterrupt = null;
public TimeOut() {
threadToInterrupt = Thread.currentThread();
setDaemon(true);
}
public void run() {
try { sleep(10000); }
catch(InterruptedException ex) {}
threadToInterrupt.interrupt();
}
}
}
注意:線程處於寫文件狀態時,調用 interrupt() 不會中斷線程。