長按掃碼關注,分享互聯網公司關注的技術堆疊

1.執行緒的創建幾種方法:
- 實作 Runnable 介面
- 繼承Thread類,
- 執行緒池創建執行緒,
- 有回傳值的 Callable 創建執行緒
- 其他創建方式 定時器 Timer,
- 其他創建方法:匿名內部類,lambda 運算式,
2.為什么實作 Runnable 介面比繼承 Thread 類實作執行緒要好?
- 1.首先,我們從代碼的架構考慮,實際上,Runnable 里只有一個 run() 方法,它定義了需要執行的內容,在這種情況下,實作了 Runnable 與 Thread 類的解耦,Thread 類負責執行緒啟動和屬性設定等內容,權責分明,
- 2.性能角度:Thread 每次需要維護執行緒的生命周期,從創建到銷毀的程序,Runnable 可以放到執行緒池中使用,降低性能開銷,
- 3.代碼擴展性:Java 語言不支持雙繼承,如果我們的類一旦繼承了 Thread 類,那么它后續就沒有辦法再繼承其他的類,這樣一來,如果未來這個類需要繼承其他類實作一些功能上的拓展,它就沒有辦法做到了,相當于限制了代碼未來的可拓展性,
3.如何正確停止執行緒?為什么 volatile 標記位的停止方法是錯誤的?
-
通常情況下,我們不會手動停止一個執行緒,而是允許執行緒運行到結束,然后讓它自然停止,但是依然會有許多特殊的情況需要我們提前停止執行緒,比如:用戶突然關閉程式,或程式運行出錯重啟等,
-
在這種情況下,即將停止的執行緒在很多業務場景下仍然很有價值,尤其是我們想寫一個健壯性很好,能夠安全應對各種場景的程式時,正確停止執行緒就顯得格外重要,但是Java 并沒有提供簡單易用,能夠直接安全停止執行緒的能力,
-
對于 Java 而言,最正確的停止執行緒的方式是使用 interrupt,但 interrupt 僅僅起到通知被停止執行緒的作用,而對于被停止的執行緒而言,它擁有完全的自主權,它既可以選擇立即停止,也可以選擇一段時間后停止,也可以選擇壓根不停止,
-
Thread.sleep(1000000); 可以使用 thread.interrupt(); 進行中斷,觸發后,處于休眠中的執行緒被中斷,那么執行緒是可以感受到中斷信號的,并且會拋出一個 InterruptedException 例外,同時清除中斷信號,將中斷標記位設定成 false,這樣一來就不用擔心長時間休眠中執行緒感受不到中斷了,因為即便執行緒還在休眠,仍然能夠回應中斷通知,并拋出例外,
-
對于拋出的例外,應該向上層上報,而不是自己吞并,例外交由呼叫方處理,還可以在catch陳述句中再次中斷執行緒,因為如果執行緒在休眠期間被中斷,那么會自動清除中斷信號,如果這時手動添加中斷信號,中斷信號依然可以被捕捉到,這樣后續執行的方法依然可以檢測到這里發生過中斷,可以做出相應的處理,整個執行緒可以正常退出,
-
volatile 這種方法在某些特殊的情況下,比如執行緒被長時間阻塞的情況,就無法及時感受中斷,所以 volatile 是不夠全面的停止執行緒的方法,
4.執行緒是如何在 6 種狀態之間轉換的?
- 執行緒的 6 種狀態,就像生物從出生到長大、最終死亡的程序一樣,執行緒也有自己的生命周期,在 Java 中執行緒的生命周期中一共有 6 種狀態,
- New(新創建)
- Runnable(可運行)
- Blocked(被阻塞)
- Waiting(等待)
- Timed Waiting(計時等待)
- Terminated(被終止)
- 如果想要確定執行緒當前的狀態,可以通過 getState() 方法,并且執行緒在任何時刻只可能處于 1 種狀態,
-狀態流轉:

5.一共有哪 3 類執行緒安全問題?
- 1.運行結果錯誤:i++問題,
- 2.發布和初始化導致執行緒安全問題
- 3.活躍性問題:最典型的有三種,分別為死鎖、活鎖和饑餓,
6.哪些場景需要額外注意執行緒安全問題?
- 1.訪問共享變數或資源,典型的場景有訪問共享物件的屬性,訪問 static 靜態變數,訪問共享的快取,等等,
- 2.依賴時序的操作:如果我們操作的正確性是依賴時序的,而在多執行緒的情況下又不能保障執行的順序和我們預想的一致,這個時候就會發生執行緒安全問題
- 3.不同資料之間存在系結關系:第三種需要我們注意的執行緒安全場景是不同資料之間存在相互系結關系的情況,有時候,我們的不同資料之間是成組出現的,存在著相互對應或系結的關系,最典型的就是 IP 和埠號,有時候我們更換了 IP,往往需要同時更換埠號,如果沒有把這兩個操作系結在一起,就有可能出現單獨更換了 IP 或埠號的情況,而此時資訊如果已經對外發布,資訊獲取方就有可能獲取一個錯誤的 IP 與埠系結情況,這時就發生了執行緒安全問題,在這種情況下,我們也同樣需要保障操作的原子性,
- 4.對方沒有宣告自己是執行緒安全的:第四種值得注意的場景是在我們使用其他類時,如果對方沒有宣告自己是執行緒安全的,那么這種情況下對其他類進行多執行緒的并發操作,就有可能會發生執行緒安全問題,舉個例子,比如說我們定義了 ArrayList,它本身并不是執行緒安全的,如果此時多個執行緒同時對 ArrayList 進行并發讀/寫,那么就有可能會產生執行緒安全問題,造成資料出錯,而這個責任并不在 ArrayList,因為它本身并不是并發安全的,
7.為什么多執行緒會帶來性能問題?
- 調度開銷
- 背景關系切換
- 快取失效
- 協作開銷
8.使用執行緒池比手動創建執行緒好在哪里?
- 1.執行緒池可以解決執行緒生命周期的系統開銷問題,同時還可以加快回應速度,因為執行緒池中的執行緒是可以復用的,我們只用少量的執行緒去執行大量的任務,這就大大減小了執行緒生命周期的開銷,而且執行緒通常不是等接到任務后再臨時創建,而是已經創建好時刻準備執行任務,這樣就消除了執行緒創建所帶來的延遲,提升了回應速度,增強了用戶體驗,
- 2.執行緒池可以統籌記憶體和CPU 的使用,避免資源使用不當,執行緒池會根據配置和任務數量靈活地控制執行緒數量,不夠的時候就創建,太多的時候就回收,避免執行緒過多導致記憶體溢位,或執行緒太少導致 CPU 資源浪費,達到了一個完美的平衡,
- 3.執行緒池可以統一管理資源,比如執行緒池可以統一管理任務佇列和執行緒,可以統一開始或結束任務,比單個執行緒逐一處理任務要更方便、更易于管理,同時也有利于資料統計,比如我們可以很方便地統計出已經執行過的任務的數量,
本文由博客群發一文多發等運營工具平臺 OpenWrite 發布
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/231285.html
標籤:Java
