我們知道像stop、suspend這幾種中斷或者阻塞線程的方法在較高java版本中已經被標記上了@Deprecated過期標簽,那么為什么她們曾經登上了java的歷史舞臺而又漸漸的推出了舞臺呢,到底是人性的扭曲還是道德的淪喪呢,亦或是她們不思進取被取而代之呢,如果是被取而代之,那么取而代之的又是何方人也,本文我們將一探究竟。
一、stop的落幕首先stop方法的作用是什么呢,用java源碼中的一句注釋來了解一下:Forces the thread to stop executing.,即強制線程停止執行,‘Forces’似乎已經透漏出了stop方法的蠻狠無理。那么我們再看看java開發者是怎們解釋stop被淘汰了的。
我們從中可以看出以下幾點:
stop這種方法本質上是不安全的
使用Thread.stop停止線程會導致它解鎖所有已鎖定的監視器,即直接釋放當前線程已經獲取到的所有鎖,使得當前線程直接進入阻塞狀態
我們舉例來看一下上邊提到的兩點:
public static void main(String[] args) throws InterruptedException {
Object o1=new Object();
Object o2=new Object();
Thread t1=new Thread(()-》{
synchronized (o1)
{
synchronized (o2)
{
try {
System.out.println(“t1獲取到鎖”);
Thread.sleep(5000);
System.out.println(“t1結束”);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
t1.start();
Thread.sleep(1000);
Thread t2=new Thread(()-》{
synchronized (o1)
{
synchronized (o2)
{
try {
System.out.println(“t2獲取到鎖”);
Thread.sleep(5000);
System.out.println(“t2結束”);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
t2.start();
t1.stop();
}
運行結果:
可以看到,當線程t1在獲取到o1和o2兩個鎖開始執行,在還沒有執行結束的時候,主線程調用了t1的stop方法中斷了t1的執行,釋放了t1線程獲取到的所有鎖,中斷后t2獲取到了o1和o2鎖,開始執行直到結束,而t1卻夭折在了sleep的時候,sleep后的代碼沒有執行。
因此使用stop我們在不知道線程到底運行到了什么地方,暴力的中斷了線程,如果sleep后的代碼是資源釋放、重要業務邏輯等比較重要的代碼的話,亦或是其他線程依賴t1線程的運行結果,那直接中斷將可能造成很嚴重的后果。
那么不建議使用stop中斷線程我們應該怎么去優雅的結束一個線程呢,我們可以存java開發者的注釋中窺探到一種解決方案:
可以看到java開發者推薦我們使用以下兩種方法來優雅的停止線程:
1.定義一個變量,由目標線程去不斷的檢查變量的狀態,當變量達到某個狀態時停止線程。
代碼舉例如下:
volatile static boolean flag=false;
public static void main(String[] args) throws InterruptedException {
Object o1=new Object();
Thread t1=new Thread(()-》{
synchronized (o1)
{
try {
System.out.println(“t1獲取到鎖”);
while (!flag)
Thread.sleep(5000);//執行業務邏輯
System.out.println(“t1結束”);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t1.start();
Thread.sleep(1000);
Thread t2=new Thread(()-》{
synchronized (o1)
{
try {
System.out.println(“t2獲取到鎖”);
Thread.sleep(5000);//執行業務邏輯
System.out.println(“t2結束”);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t2.start();
flag=true;
}
運行結果:
2.使用interrupt方法中斷線程。
代碼舉例如下:
public static void main(String[] args) throws InterruptedException {
Object o1=new Object();
Thread t1=new Thread(()-》{
synchronized (o1)
{
System.out.println(“t1獲取到鎖”);
while (!Thread.currentThread().isInterrupted()) {
for (int i = 0; i 《 100; i++) {
if(i==50)
System.out.println();
System.out.print(i+“ ”);
}
System.out.println();
}
System.out.println(“t1結束”);
}
});
t1.start();
Thread t2=new Thread(()-》{
synchronized (o1)
{
try {
System.out.println(“t2獲取到鎖”);
Thread.sleep(5000);//執行業務邏輯
System.out.println(“t2結束”);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t2.start();
t1.interrupt();
}
運行結果:
我們用while (!Thread.currentThread().isInterrupted())來不斷判斷當前線程是否被中斷,中斷的話則讓線程自然消亡并釋放鎖。可以看到調用interrupt方法后并不會像stop那樣暴力的中斷線程,會等到當前運行的邏輯結束后再檢查是否中斷,非常的優雅。另外,關注Java知音公眾號,回復“后端面試”,送你一份面試題寶典!
注:運行舉例代碼可能不會打印出數字,這是因為t1線程運行到while(!Thread.currentThread().isInterrupted())時,主線程已經調了interrupt方法,因此多次運行可能會打印出數字。
二、suspend的落幕suspend方法的作用是掛起某個線程直到調用resume方法來恢復該線程,但是調用了suspend方法后并不會釋放被掛起線程獲取到的鎖,正因如此就給suspend和resume這哥倆貼上了容易引發死鎖的標簽,當然這也正是導致suspend和resume退出歷史舞臺的罪魁禍首。同樣我們看看java開發者為suspend的淘汰給出的理由:
從中我們可以得出以下結論:
suspend具有天然的死鎖傾向
當某個線程被suspend后,該線程持有的鎖不會被釋放,其他線程也就不能訪問這些資源
suspend某個線程后,如果在resume的過程中出現異常導致resume方法執行失敗,則lock無法釋放,導致死鎖
接下來模擬一下由suspend引起的死鎖場景,Talk is cheap,show my code:
public static void main(String[] args) throws InterruptedException {
Object o1=new Object();
Object o2=new Object();
Thread t1=new Thread(()-》{
synchronized (o1)
{
System.out.println(“t1獲取到o1鎖開始執行”);
try {
Thread.sleep(5000);//模擬執行業務邏輯
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(“t1執行結束”);
}
});
t1.start();
Thread t2=new Thread(()-》{
synchronized (o2)
{
System.out.println(“t2獲取到o2開始執行”);
try {
Thread.sleep(2000);//執行耗時業務
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (o1)
{
System.out.println(“t2獲取到o1鎖開始繼續執行”);
}
System.out.println(“t2執行結束”);
}
});
t2.start();
Thread.sleep(1000);
t1.suspend();
//假設拋出了一個未知異常
int i=1/0;
t1.resume();
}
運行結果:
可以看到,整個程序卡的死死的,在調用resume恢復t1線程之前拋出了一個未知異常,導致t1一直掛起進而無法釋放o1鎖,而t2需要獲取到o1鎖后才能繼續執行,但苦苦等待,奈何o1被t1拿捏的死死的,從此整個程序就陷入了無盡的等待中----死鎖。
作者丨浪舟子
blog.csdn.net/qq_40400960/article/details/112651249
編輯:jq
-
中斷
+關注
關注
5文章
898瀏覽量
41514
原文標題:為什么強烈不推薦使用stop、suspend方法來中斷線程?
文章出處:【微信號:AndroidPush,微信公眾號:Android編程精選】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論