線程結束源碼
❶ android 為什麼不建議使用Thread.stop
當調用Thread.stop()方法時,會發生以下兩種事情:
1. 即可拋出ThreadDeath異常,在線程的run()方法裡面,任何一刻都可能拋出ThreadDeath Error,包括在catch或者finally語句中。
2. 釋放該線程的所有鎖。
當線程拋出ThreadDeath異常時,會導致線程的run()方法突然返回來達到停止該線程的目的。這個異常可以在該線程run()任意一個執行點拋出。原則上只要一調用thread.stop()方法,線程會立即停止,並拋出ThreadDeath error,查看了Thread的源代碼後才發現,原先Thread.stop0()方法是同步的,而我們工作線程的run()方法也是同步,那麼這樣會導致主線程和工作線程共同爭用同一個鎖(工作線程對象本身),由於工作線程在啟動後就先獲得了鎖,所以無論如何,當主線程在調用thread.stop()時,它必須要等到工作線程的run()方法執行結束後才能進行。
因此,thread.stop()是不安全的,主要針對於於:釋放改線程所持有的所有的鎖,而鎖的突然釋放會導致被保護的數據的不一致性。
正確停止線程總結起來是以下三點:
1. 使用violate boolean 變數來表示線程是否停止;
2. 停止線程時,需要調用停止線程的interrupt()方法,因為線程有可能在wait()或者sleep(),提高停止線程的及時性;
3. 對於blocking IO的處理,盡量使用interruptibleChannel來代替 blocking IO。
❷ 如何優雅地結束一個線程
首先謝謝邀請
在本文中,我們將討論結束java線程的簡潔方法,這是必要的,因為Java已經棄用了Thread.stop()方法。
Thread.stop, Thread.suspend, Thread.resume and Runtime.runFinalizersOnExit由於一些潛在的線程安全問題, Oracle已棄用 。很少有公認的和廣為接受的方法來實現這一點,在本文中,我們將討論2 個用Java結束線程的方法。
使用標志
中斷線程。
1.使用標志
一種簡單的方法是使用線程來指示線程是否正在運行,並使用此標志根據您的要求採取糾正措施,下面是一個示例代碼,概述了如何使用標志來殺死Java線程。
在上面的例子中。我們可以通過將運行變數設置為false來控制執行。在我們的示例中,我們使用AtomicBoolean了並發,如果您不想使用它(不推薦),您需要確保Boolean您在代碼應該是易變的。可以使用 volatile代替他。
2.中斷線程
以上代碼看起來不錯,但在採取上述方法之前需要考慮一些要點
如果我們有很多線程,它將變得更加復雜,我們需要確保使用join()方法完成這些線程。
我們真的需要定義一個布爾標志,因為Java已經使用中斷標志提供了這個功能嗎?
在這個代碼塊中有幾件非常重要的事情
我們不會吞下異常,而是將其傳遞給系統,以確保系統根據此異常採取糾正措施
在上面的例子中,我們捕獲InterruptedException並立即用於立即 Thread.currentThread().interrupt() 中斷我們的線程。這是必需的,因為一旦拋出異常就中斷了中斷標志,並且如果我們的代碼在嵌套循環中運行,它可能會導致一些問題。
總而言之,如果你仍然想要使用標志方法,那麼Thread.interrupt()結束java線程的首選/推薦方法是你可能必須等待所有阻塞操作完成才能使用基於標志的邏輯。
文版權歸是三僡然所有,轉載請標明出處。歡迎轉載,歡迎評論,歡迎分享。如果你有文章想分享可以聯系我。
❸ 線程池中空閑的線程處於什麼狀態
一:阻塞狀態,線程並沒有銷毀,也沒有得到CPU時間片執行;
源碼追蹤:
for (;;) {
...
workQueue.take();
...
}
public E take()...{
...
while (count.get() == 0) { / /這里就是任務隊列中的消息數量
notEmpty.await();
}
...
}
public final void await()...{
...
LockSupport.park(this);
...
}
繼續往下:
public static void park(Object blocker) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
U.park(false, 0L);
setBlocker(t, null);
}
private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
//線程調用該方法,線程將一直阻塞直到超時,或者是中斷條件出現。
public native void park(boolean isAbsolute, long time);
上面就是java11線程池中阻塞的源碼追蹤;
二.對比object的wait()方法:
@FastNative
public final native void wait(long timeout, int nanos) throws InterruptedException;
還有Thread的sleep() 方法:
@FastNative
private static native void sleep(Object lock, long millis, int nanos)throws...;
可見,線程池中使用的阻塞方式並不是Object中的wait(),也不是Thread.sleep() ;
這3個方法最終實現都是通過c&c++實現的native方法.
三.在<<Java虛擬機(第二版)>>中,對線程狀態有以下介紹:
12.4.3狀態轉換
Java語言定義了5種線程狀態,在任意一個時間點,一個線程只能有且只有其中的一種
狀態,這5種狀態分別如下。
1)新建(New):創建後尚未啟動的線程處於這種狀態。
2)運行(Runable):Runable包括了操作系統線程狀態中的Running和Ready,也就是處於此
狀態的線程有可能正在執行,也有可能正在等待著CPU為它分配執行時間。
3)無限期等待(Waiting):處於這種狀態的線程不會被分配CPU執行時間,它們要等待被
其他線程顯式地喚醒。以下方法會讓線程陷入無限期的等待狀態:
●沒有設置Timeout參數的Object.wait()方法。
●沒有設置Timeout參數的Thread.join()方法。
●LockSupport.park()方法。
4)限期等待(Timed Waiting):處於這種狀態的線程也不會被分配CPU執行時間,不過無
須等待被其他線程顯式地喚醒,在一定時間之後它們會由系統自動喚醒。以下方法會讓線程
進入限期等待狀態:
●Thread.sleep()方法。
●設置了Timeout參數的Object.wait()方法。
●設置了Timeout參數的Thread.join()方法。
●LockSupport.parkNanos()方法。
●LockSupport.parkUntil()方法。
5)阻塞(Blocked):線程被阻塞了,「阻塞狀態」與「等待狀態」的區別是:「阻塞狀態」在等
待著獲取到一個排他鎖,這個事件將在另外一個線程放棄這個鎖的時候發生;而「等待狀
態」則是在等待一段時間,或者喚醒動作的發生。在程序等待進入同步區域的時候,線程將
進入這種狀態。
結束(Terminated):已終止線程的線程狀態,線程已經結束執行。