1.什么是線程 ?線程和進程的區別 ?
線程是操作系統能夠進行運算調度的最小單位,它被包含在進程之中,是進程中的實際運作單位。而進程是系統中
正在運行的一個程序,程序一旦運行就是進程。
區別:(1)線程是 CPU 調度的基本單位,沒有獨立的地址空間;進程是資源分配的基本單位,有獨立的地址空
間。
(2)進程間切換代價大,線程間切換代價小。
(3)進程擁有的資源多,線程擁有的資源少。
(4)一個進程無法直接訪問另一個進程的資源,同一進程內的多個線程可以共享該進程的資源。
(5)線程屬于進程,不能獨立執行,每一個進程至少要有一個線程,并成為主線程。
2.描述 CPU 和多線程的關系 ?
(1)第一階段:單CPU時代,單CPU在同一時間點,只能執行單一線程。
(2)第二階段:單CPU多任務階段,計算機在同一時間點,并行執行多個線程。但這并非真正意義上的同時執
行,而是多個任務共享一個CPU,操作系統協調 CPU 在某個時間點執行某個線程,因為CPU在線程之間切換比較
快,給人的感覺就好像是多個任務在同時運行。
(3)第三階段:多 CPU 多任務階段,真正實現了在同一時間點運行多個線程。
3.什么是線程安全和線程不安全 ?
(1)線程安全:指多個線程在執行同一段代碼的時候采用加鎖機制,使每次的執行結果和單線程執行的結果都是
一樣的,不存在執行程序時出現意外結果。
(2)線程不安全:指不提供加鎖保護機制,有可能出現多個線程先后更改數據造成所得到的數據是臟數據。
4.描述線程的生命周期 ?(畫圖)
線程的生命周期包括五個階段:創建、就緒、運行、阻塞、銷毀。
(1)創建:用 new 關鍵字建立一個線程后,該線程對象就處于創建狀態,處于新生狀態的線程有自己的內存空
間,通過調用 start() 方法進入就緒狀態。
(2)就緒:調用線程的 start() 方法后,線程進入就緒狀態,這時候線程處于等待 CPU 分配資源階段,誰先搶的
CPU資源,誰開始執行。
(3)運行:當就緒的線程被調度并獲得 CPU 資源時,便進入運行狀態,run() 方法定義了線程的操作和功能。
(4)阻塞:在運行狀態的時候,可能因為某些原因導致運行狀態的線程變成了阻塞狀態,比如 sleep()、wait() 之
后線程就處于了阻塞狀態,這個時候需要其它機制將處于阻塞狀態的線程喚醒,比如調用 notify() 或者 notifyAll()
方法,喚醒的線程不會立刻執行 run() 方法,他們要再次等待 CPU 分配資源進入運行狀態。
(5)銷毀:如果線程正常執行完畢后或線程被提前強制性的終止或者出現異常導致結束,那么線程就要被銷毀,
同時釋放資源。
5.wait、sleep、join、yield 的區別 ?
(1)wait:wait 方法是屬于 Object 類中的,wait 過程中線程會釋放對象鎖,只有當其它線程調用 notify 時才能
喚醒此線程。wait 使用時必須先獲取對象鎖,即必須在 Synchronized 修飾的代碼塊中使用,那么相應的 notify
方法同樣也必須在 Synchronized 修飾的代碼塊中使用,如果沒有在 Synchronized 修飾的代碼塊中使用,那么在
運行時就會拋出 IllegalMonitorStateException 異常。
(2)sleep:在指定時間內讓當前正在執行的線程暫停執行,sleep 過程中線程不會釋放鎖,只會阻塞線程,當到
了指定的時間后才會自動恢復運行狀態。
(3)join:等待調用 join 方法的線程結束之后,程序將會繼續執行。
(4)yield:暫停當前正在執行的線程對象,yield 過程中不會釋放資源鎖,和 sleep 不同的是 yield 方法并不會讓
線程進入阻塞狀態,而是讓線程重回就緒狀態,允許其它具有相同優先同級的線程獲得運行的機會。
6.Synchronized 和 Lock 的區別 ?
(1)Lock 是一個接口,而 Synchronized是 java 的一個關鍵字。
(1)Lock 有比 Synchronized 更精確的線程語義和更好的性能。
(2)Synchronized 會自動釋放鎖,從而可以避免死鎖,而 Lock 一定要求程序員手工釋放,可能引起死鎖,并且
必須在 finally 從句中釋放。
7.ThreadLocal、Volatile、Synchronized 的作用和區別 ?
(1)ThreadLocal 不是為了解決多線程訪問共享變量,而是為每個線程創建一個單獨的變量副本,提供了保持對
象的方法和避免參數傳遞的復雜性。
(2)Volatile 主要是用來在多線程中同步變量。
(3)Synchronized 關鍵字保證了數據讀寫一致和可見性等問題。
8.同步方法和同步代碼塊哪個更好 ?
(1)同步代碼塊是更好的選擇,因為它不會鎖住整個對象,而同步方法會鎖住整個對象,哪怕這個類中有多個不
相關聯的同步代碼塊,這通常會導致他們停止執行并需要等待獲得這個對象上的鎖。
(2)同步代碼塊更符合開發調用的原則,只要在需要鎖住的代碼塊中鎖住相應的對象,這樣從側面來說也可以避
免死鎖。
-
同步方法使用 Synchronized 修飾方法,在調用該方法前,需要獲得內置鎖(java每個對象都有一個內置
鎖),否則就處于阻塞狀態。
-
同步代碼塊使用 Synchronized(object){} 進行修飾,在調用該代碼塊時,需要獲得內置鎖,否則就處于阻塞狀
態。
9.什么是死鎖 ?如何避免死鎖 ?
線程死鎖:是指由于兩個或者多個線程競爭資源或者互相持有對方所需要的資源,導致這些線程處于等待狀態,無
法前往執行,當兩個線程相互等待對方釋放資源時,就會發生死鎖。
(1)避免多次鎖定。
(2)具有相同的加鎖順序。
(3)使用定時鎖。
(5)死鎖檢測。
10.常見的線程池叫什么 ?線程池的作用是什么 ?
常見的線程池有:FixedThreadPool、CachedThreadPool、SingleThreadPool、ScheduledThreadPool。
作用:(1)減少在創建和銷毀線程上所花的時間以及系統資源的開銷 。
? (2)如果不使用線程池,有可能造成系統創建大量線程而導致消耗完系統內存以及 ”過度切換”。