併發程式設計——如何終止執行緒

超Code發表於2021-08-10

前言

今天簡單的講一講如何終止執行緒。

如果對於執行緒的建立方式不太瞭解,推薦觀看併發程式設計——認識java裡的執行緒
對於執行緒狀態及其切換不瞭解的,推薦觀看併發程式設計——Java執行緒的6種狀態及切換
對於執行緒的啟動不了解的,推薦觀看併發程式設計——執行緒的啟動

終止執行緒

終止執行緒的方式

1、使用標記變數

我們通過繼承Thread來建立一個自定義的執行緒類,裡面live這個屬性是用來控制執行緒是否終止

使用main方法去測試,啟動執行緒,然後延遲20毫秒,然後我們去改變這個live,使其跳出迴圈,繼續往下走,執行完run,達到一個執行緒自然執行完終止的效果。

下面是執行結果,看到結果如我們預想的那樣,跳出迴圈之後,現成終止。

2、使用stop方法

首先看一下stop的原始碼,我們發現這個方法使用了@Deprecated註解,表示不推薦使用,是被廢除的。
這個方法目前還是能夠達到終止執行緒的目的,但是這個方法是不安全的,或者說是比較暴力的中斷執行,導致是程式碼不能執行完,邏輯不完整,而且會釋放所有鎖資源,影響原子操作,資料不一致問題。所以如果你不知道當前執行緒的一些執行情況,佔用資源的情況的話,還是不推薦使用。
JDK 文件中還引入用一篇文章來解釋了棄用這些方法的原因:《Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?》

為什麼棄用stop:

  1. 呼叫 stop() 方法會立刻停止 run() 方法中剩餘的全部工作,包括在 catch 或 finally 語句中的,並丟擲ThreadDeath異常(通常情況下此異常不需要顯示的捕獲),因此可能會導致一些清理性的工作的得不到完成,如檔案,資料庫等的關閉。
  2. 呼叫 stop() 方法會立即釋放該執行緒所持有的所有的鎖,導致資料得不到同步,出現資料不一致的問題。

3、使用interrupt方法

跟interrupt在Thread類中相關的有三個方法,分別是interrupt(),interrupted(),isInterrupted()。
下面來分析一下這三個方法的區別,以及用法。

isInterrupted()
通過物件導向思想我們大概就能猜出來,再看到它的返回值是一個boolean型別,那就十之八九能知道這個方法就是獲取當前這個中斷訊號的值是什麼。

繼續深入點進去發現呼叫的是一個native本地方法,接收一個是否清除Interrupted標誌位的引數,isInterrupted()傳遞過來的是一個false,說明不會去清除Interrupted標誌位。
下面測試結果發現這個方法會在中斷執行緒之後,不會對Interrupted標誌位做清除工作,還是true。

interrupted()

首先我們看到這個方法是一個靜態方法,interrupted()也呼叫了isInterrupted(true)方法,不過它傳遞的引數是true,表示將會清除中斷標誌位。
下面測試結果發現這個方法會在中斷執行緒之後,會將Interrupted標誌位清除,發現清除之後的結果為false。

interrupt()

前面兩個是判斷是否中斷的方法,而interrupt()就是真正觸發中斷的方法。
中斷執行緒,其實是設定執行緒的標識位為true。
interrupt()原始碼:

1、使用isInterrupted()測試程式碼:

執行結果圖:我們發現呼叫interrupt()之後,標誌位變為true,跳出迴圈,達到一箇中斷現成的目的。

2、使用interrupted()測試程式碼:

執行結果圖:我們發現呼叫interrupt()之後,標誌位變為true,第二次進入迴圈,發現不符合,跳出迴圈,達到一箇中斷現成的目的。但是使用interrupted()會清除標誌位,所以會發現最後一次列印的和之前不一樣了,變為false。

這三個方法要搞清楚,這塊可能會在面試的時候會問你這三個方法的區別。

感謝諸君的觀看,文中如有紕漏,歡迎在評論區來交流。如果這篇文章幫助到了你,歡迎點贊?關注。

相關文章