怎么在java中關閉一個thread
我們經常需要在java中用到thread,我們知道thread有一個start()方法可以開啟一個線程。那么怎么關閉這個線程呢?
有人會說可以用Thread.stop()方法。但是這個方法已經被廢棄了。
根據Oracle的官方文檔,Thread.stop是不安全的。因為調用stop方法的時候,將會釋放它獲取的所有監視器鎖(通過傳遞ThreadDeath異常實現)。如果有資源該監視器鎖所保護的話,就可能會出現數據不一致的異常。並且這種異常很難被發現。 所以現在已經不推薦是用Thread.stop方法了。
那我們還有兩種方式來關閉一個Thread。
- Flag變量
如果我們有一個無法自動停止的Thread,我們可以創建一個條件變量,通過不斷判斷該變量的值,來決定是否結束該線程的運行。
public class KillThread implements Runnable {
private Thread worker;
private final AtomicBoolean running = new AtomicBoolean(false);
private int interval;
public KillThread(int sleepInterval) {
interval = sleepInterval;
}
public void start() {
worker = new Thread(this);
worker.start();
}
public void stop() {
running.set(false);
}
public void run() {
running.set(true);
while (running.get()) {
try {
Thread.sleep(interval);
} catch (InterruptedException e){
Thread.currentThread().interrupt();
log.info("Thread was interrupted, Failed to complete operation");
}
// do something here
}
log.info("finished");
}
public static void main(String[] args) {
KillThread killThread= new KillThread(1000);
killThread.start();
killThread.stop();
}
}
上面的例子中,我們通過定義一個AtomicBoolean 的原子變量來存儲Flag標志。
我們將會在后面的文章中詳細的講解原子變量。
- 調用interrupt()方法
通過調用interrupt()方法,將會中斷正在等待的線程,並拋出InterruptedException異常。
根據Oracle的說明,如果你想自己處理這個異常的話,需要reasserts出去,注意,這里是reasserts而不是rethrows,因為有些情況下,無法rethrow這個異常,我們需要這樣做:
Thread.currentThread().interrupt();
這將會reasserts InterruptedException異常。
看下我們第二種方法怎么調用:
public class KillThread implements Runnable {
private Thread worker;
private final AtomicBoolean running = new AtomicBoolean(false);
private int interval;
public KillThread(int sleepInterval) {
interval = sleepInterval;
}
public void start() {
worker = new Thread(this);
worker.start();
}
public void interrupt() {
running.set(false);
worker.interrupt();
}
public void stop() {
running.set(false);
}
public void run() {
running.set(true);
while (running.get()) {
try {
Thread.sleep(interval);
} catch (InterruptedException e){
Thread.currentThread().interrupt();
log.info("Thread was interrupted, Failed to complete operation");
}
// do something here
}
log.info("finished");
}
public static void main(String[] args) {
KillThread killThread= new KillThread(1000);
killThread.start();
killThread.interrupt();
}
}
上面的例子中,當線程在Sleep中時,調用了interrupt方法,sleep會退出,並且拋出InterruptedException異常。
本文的例子請參考https://github.com/ddean2009/learn-java-concurrency/tree/master/kill-thread
更多教程請參考 flydean的博客