筆者是廣州的java程序員,剛畢業半年,工做之餘寫博客,若是以爲個人文章寫得不錯,能夠關注個人微信公衆號(J2彬彬),裏面會有更多精彩內容。從2018年8月份開始寫博客,但願往後寫出更多通俗易懂的技術文章與你們一同分享。java
你有沒有想過,如何中止一個線程?不少人首先會想到Thread.stop()方法,可是這個方法已通過時,不推薦使用,由於這個方法會帶來安全問題,什麼安全問題呢?後面會有詳細說明。咱們先講講目前JDK API推薦使用中止線程的方法Thread.interrupt()方法。程序員
既然不能直接stop線程,那麼只有一種方法可讓線程結束,那就是讓run方法運結束。 Thread.interrupt()表明的意思是「中止,停止」。可是這個方法須要加入一個判斷才能夠完成線程的中止。一旦檢測到線程處於中斷狀態,那麼就有機會結束run方法。 下面以一個代碼示例看看它是如何中止線程的?安全
package com.bingo.thread.stopThread;
/** * Created with IntelliJ IDEA. * Description: 中止線程不推薦使用stop方法,此方法不安全,咱們可使用Thread.interrupt() * User: bingo */
public class Run {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
myThread.interrupt();
System.out.println("end...");
}
}
class MyThread extends Thread{
@Override
public void run() {
super.run();
for (int i = 0; i < 10000 ; i++) {
if(this.isInterrupted()){
System.out.println("已是中止狀態了,我要退出了");
break;
}
System.out.println("i="+(i+1));
}
}
}
複製代碼
運行結果:微信
i=1
......
i=3102
i=3103
i=3104
i=3105
i=3106
i=3107
i=3108
end...
已是中止狀態了,我要退出了
複製代碼
運行結果咱們能夠看到,當myThread線程的循環運行到i=3108的時候,因爲線程被中斷,而跳出循環,這個例子很好詮釋了interrupt方法的做用。多線程
package com.bingo.thread.stopThread;
/** * Created with IntelliJ IDEA. * Description: interrupt能夠清除線程的凍結狀態,讓線程恢復到可運行的狀態上來。 * User: bingo */
public class Run2 {
public static void main(String[] args) {
MyThread2 thread = new MyThread2();
thread.start();
thread.interrupt();
System.out.println("main end...");
}
}
class MyThread2 extends Thread{
@Override
public void run() {
System.out.println("run begin...");
try {
Thread.sleep(1000000);
} catch (InterruptedException e) {
System.out.println("run 在沉睡中被停止,進入catch");
e.printStackTrace();
}
System.out.println("run end...");
}
}
複製代碼
運行結果:ide
main end...
run begin...
run 在沉睡中被停止,進入catch
run end...
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at com.bingo.thread.stopThread.MyThread2.run(Run2.java:26)
複製代碼
從運行結果咱們能夠看到,原本run方法睡眠時間爲1000秒,可是打印結果倒是瞬間的,其實sleep已經被interrupt方法給打斷,此時線程凍結狀態被清除,並拋出異常,被catch捕獲,打印異常信息。學習
下圖是JDK API對stop方法的描述,能夠看到已過期,不推薦使用,並告訴咱們此方法爲什麼不安全? this
若是某個線程加鎖,stop方法中止該線程時會把鎖釋放掉,可能形成數據不一致的狀況。下面代碼能夠說明此問題。package com.bingo.thread.stopThread;
/** * Created with IntelliJ IDEA. * Description: stop()方法爲什麼不安全?下面例子可解答 * User: bingo */
public class StopTest {
public static void main(String[] args) {
try {
SynchrionzedObject object = new SynchrionzedObject();
MyThread3 t = new MyThread3(object);
t.start();
Thread.sleep(500);
t.stop();
System.out.println(object.getUsername()+" "+object.getPassword());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class SynchrionzedObject{
private String username = "a";
private String password = "aa";
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
public synchronized void printString(String username,String password){
try {
this.username = username;
Thread.sleep(10000);
this.password = password;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class MyThread3 extends Thread{
private SynchrionzedObject object;
public MyThread3(SynchrionzedObject object){
this.object = object;
}
@Override
public void run() {
object.printString("b", "bb");
}
}
複製代碼
運行結果:spa
b aa
複製代碼
從上面例子咱們能夠看到雖然printString方法加了鎖,可是run方法運行過程當中忽然被stop了,鎖被釋放,MyThread線程只對username進行了賦值,而password賦值動做未執行,此時形成數據不一致。線程
其實java多線程不少方法內部都是native方法,也就是基於JVM內部實現的,因此咱們有必要結合JVM一塊兒學習這部分的內容。技術的進步須要每一個小小的積累,才能走得更遠,更長久。