java 多線程之使用 interrupt 停止線程的幾種方法

停止線程是java多線程開發中很重要的技術點,實際工作中很多業務都有類似的需求,掌握此技術可以對業務中所需停止的線程做有效的處理。但是停止線程在java語言中並不像break語句中那樣乾脆簡單,還需要我們做一下技巧性的處理。 如何更好的停止一個線程是我們應該要考慮的問題,停止一個線程意味著在線程處理完任務之前停掉正在做的操作,即放棄當前的操作。停止一個線程在之前老的JDK中使用的是 Thread.stop() 方法,但是後面發現這種處理方法是很危險而且不安全的,由於stop()方法已經在JDK中被標明是“作廢/過期”的方法,顯然它在功能上是具有缺陷的。作為一個負責的java工程師,最好是不要去使用它, 因為使用stop()方法釋放鎖將會給數據造成不一致性的結果。如果出現這種情況,程序處理的數據可能遭到破壞,最終導致程序執行流程錯誤。 大多數停止一個線程的操作使用的是 Thread.interrupt() 方法,雖然方法名是“終止,停止”的意思,但是這個方法不會直接終止一個正在運行的線程還需要加入一個判斷才可以完成線程的停止。 此外,在java中有以下的3種方法可以終止正在運行的線程:

  1. 使用退出標誌,使線程正常退出,也就是當run方法完成後才停止;
  2. 就是我們上面所說的使用stop方法強行終止線程,是過期作廢的方法,這種方法可以排除不用;
  3. 使用interrupt方法終止線程。

第一種使用退出標誌的方法樓主不做介紹,具體可以參考其他博客,都大同小異,樓主寫這篇博客主要是探索使用interrupt停止線程的幾種方法的優劣。

異常法停止線程

首先我們用for-break方式停止線程:

public class ExceptionInterrupt extends Thread {
@Override
public void run() {
super.run();
for (int i = 0; i < 500000; i++) {
if (this.isInterrupted()) {
System.out.println("已經是停止狀態了!我要退出了!");
break;
}
System.out.println("i=" + (i + 1));
}
System.out.println("我被輸出,如果此代碼是for又繼續運行,線程並未停止!");
}
public static void main(String[] args) {
ExceptionInterrupt thread = new ExceptionInterrupt();
thread.start();

try {
Thread.sleep(2000);
thread.interrupt();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("end!");
}
}
複製代碼

打印結果如下:

......
i=421200
i=421201
i=421202
i=421203
i=421204
i=421205
i=421206
i=421207
i=421208
i=421209
已經是停止狀態了!我要退出了!
我被輸出,如果此代碼是for又繼續運行,線程並未停止!
end!
複製代碼

我們發現,上面的示例雖然停止了線程,但是如果for語句下面還有語句,那麼還是會繼續執行。所以我們這裡用異常法來停止線程,就不會繼續執行for後面的業務邏輯了。

public class ExceptionInterrupt2 extends Thread {
@Override
public void run() {
super.run();
try {

for (int i = 0; i < 500000; i++) {
if (this.isInterrupted()) {
System.out.println("已經是停止狀態了!我要退出了!");
throw new InterruptedException();
}
System.out.println("i=" + (i + 1));
}
System.out.println("我在for下面");
} catch (InterruptedException e) {
System.out.println("進入ExceptionInterrupt2 類中run方法的catch了!");
e.printStackTrace();
}
}
public static void main(String[] args) {
ExceptionInterrupt2 thread = new ExceptionInterrupt2();
thread.start();
try {
Thread.sleep(2000);
thread.interrupt();
} catch (InterruptedException e) {
System.out.println("main catch");
e.printStackTrace();
}
System.out.println("end!");
}
}
複製代碼

打印結果如下:

......
i=96487
i=96488
i=96489
i=96490
i=96491
i=96492
i=96493
已經是停止狀態了!我要退出了!
進入ExceptionInterrupt2 類中run方法的catch了!
java.lang.InterruptedException
at com.thread.chapter1.ExceptionInterrupt2.run(ExceptionInterrupt2.java:20)
end!
複製代碼

在sleep()中停止線程

如果線程在sleep()狀態下停止線程,會有什麼效果呢?我們來看下面的示例:

public class SleepInterrupt extends Thread{
@Override
public void run() {
super.run();
try {
System.out.println("run begin");
Thread.sleep(200000);
System.out.println("run end");
} catch (InterruptedException e) {
System.out.println("在沉睡中被停止!進入catch!"+this.isInterrupted());
e.printStackTrace();
}
}
public static void main(String[] args) {
try {
SleepInterrupt thread=new SleepInterrupt();
thread.start();
Thread.sleep(200);
thread.interrupt();
} catch (InterruptedException e) {
System.out.println("main catch");
e.printStackTrace();
}
System.out.println("end");
}
}
複製代碼

執行結果如下:

run begin
end
在沉睡中被停止!進入catch!false
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at com.thread.chapter1.SleepInterrupt.run(SleepInterrupt.java:18)
複製代碼

從執行結果來看,如果在sleep狀態下停止某一線程,會進入catch語句,並且清除停止狀態值,使之變為false。上面的示例是先sleep然後再用interrupt()停止,與之相反的操作也要注意。

public class SleepInterrupt2 extends Thread {
@Override
public void run() {
super.run();
try {
for (int i = 0; i < 100000; i++) {
System.out.println("i=" + (i + 1));
}
System.out.println("run begin");
Thread.sleep(200000);
System.out.println("run end");
} catch (InterruptedException e) {
System.out.println("先停止,再遇到了sleep!進入catch!");
e.printStackTrace();
}
}
public static void main(String[] args) {
SleepInterrupt2 thread = new SleepInterrupt2();
thread.start();
thread.interrupt();
System.out.println("end");
}
}
複製代碼

執行結果如下:

......
i=99991
i=99992
i=99993
i=99994
i=99995
i=99996
i=99997
i=99998
i=99999

i=100000
run begin
先停止,再遇到了sleep!進入catch!
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at com.thread.chapter1.SleepInterrupt2.run(SleepInterrupt2.java:21)
複製代碼

使用return停止線程

將方法interrupted()與return結合使用也能實現停止線程的效果。

public class ReturnInterrupt extends Thread {
@Override
public void run() {
while (true) {
if (this.isInterrupted()) {
System.out.println("停止了!");
return;
}
System.out.println("time=" + System.currentTimeMillis());
}
}
public static void main(String[] args) throws InterruptedException {
ReturnInterrupt thread=new ReturnInterrupt();
thread.start();
Thread.sleep(2000);
thread.interrupt();
}
}
複製代碼

執行結果如下:

......
time=1536809054172
time=1536809054172
time=1536809054172
time=1536809054172
time=1536809054173
time=1536809054173
time=1536809054173
time=1536809054173

time=1536809054173
time=1536809054173
time=1536809054173
time=1536809054173
time=1536809054173
time=1536809054173
time=1536809054173
time=1536809054173
time=1536809054173
time=1536809054173
time=1536809054173
time=1536809054173
停止了!
複製代碼


分享到:


相關文章: