天天看點

多線程--面試題

總結一下多線程高頻面試題。

1.什麼是線程?線程和程序的差別?

線程:線程是CPU排程的最小機關,也是程式執行的最小機關。沒有單獨位址空間,線程屬于程序,不能獨立執行,每個程序至少要有一個線程,稱為主線程。

程序:程序是系統進行資源配置設定的基本機關,有獨立的記憶體位址空間;

2.描述CPU和多線程的關系

  • 第一階段,單CPU時代,單CPU在同一時間點,隻能執行單一線程。
  • 第二階段,單CPU多任務階段,計算機在同一時間點,并行執行多個線程。但這并非真正意義上的同時執行,而是多個任務共享一個CPU,作業系統協調CPU在某個時間點,執行某個線程,因為CPU線上程之間切換比較快,就好像多個任務在同時運作。
  • 第三階段,多CPU多任務階段,真正實作的,在同一時間點運作多個線程。具體到哪個線程在哪個CPU執行,這就跟作業系統和CPU本身的設計有關了。

3.什麼是線程安全/線程不安全?

線程安全:就是多線程通路時,采用了加鎖機制,當一個線程通路該類的某個資料時,進行保護,其他線程不能進行通路直到該線程讀取完,其他線程才可使用。

線程不安全:就是不提供資料通路保護,有可能出現多個線程先後更改資料造成所得到的資料是髒資料

4.描述下線程的生命周期?

(圖很重要,很多公司筆試都會要求畫出生命周期圖)

多線程--面試題
  • 初始狀态 : 線程對象建立完成 就是new建立了一個線程對象
  • 就緒狀态 : 線程可以被執行 就是調用了start()方法後的狀态
  • 運作狀态 : 線程正在運作中 就是就緒狀态的線程擷取了CPU執行權執行線程
  • 阻塞狀态 : 線程休眠 就是調用了Thread.sleep()方法使線程進入休眠
  • 等待隊列 : 線程陷入無限的等待中 就是線程執行wait()方法,進入這個狀态後
  • 鎖池狀态 : 線程被喚醒,但沒有擷取到鎖 同步鎖被别的線程占用,則該線程放入“鎖池”中,進入鎖池狀态
  • 死亡狀态 : 線程執行完畢或被關閉 就是run()方法執行完畢後,線程就進入死亡狀态

5.wait、sleep、join、yield的差別

wait:Object類的方法(notify()、notifyAll() 也是Object對象),必須放在循環體和同步代碼塊中,執行該方法的線程會釋放鎖,進入線程等待池中等待被再次喚醒(notify随機喚醒,notifyAll全部喚醒,線程結束自動喚醒)即放入鎖池中競争同步鎖

sleep:Thread類的方法,必須帶一個時間參數。會讓目前線程休眠進入阻塞狀态并釋放CPU(Sleep釋放CPU,wait 也會釋放cpu,因為cpu資源太寶貴了,隻有線上程running的時候,才會擷取cpu片段),提供其他線程運作的機會且不考慮優先級,但如果有同步鎖則sleep不會釋放鎖即其他線程無法獲得同步鎖 可通過調用interrupt()方法來喚醒休眠線程。

yield:讓出CPU排程,Thread類的方法, yield()隻是使目前線程重新回到就緒狀态,是以執行yield()的線程有可能在進入到就緒狀态後馬上又被執行。調用yield方法隻是一個建議,告訴線程排程器我的工作已經做的差不多了,可以讓别的相同優先級的線程使用CPU了,沒有任何機制保證采納。

join:一種特殊的wait,目前運作線程調用另一個線程的join方法,目前線程進入阻塞狀态直到另一個線程運作結束等待該線程終止。 注意該方法也需要捕捉異常。

6.Synchronized和Lock的差別

  • synchronized關鍵字主要解決多線程通信時候共享資料同步問題。
  • Synchronized底層使用指令碼方式來控制鎖的。Lock:底層是CAS樂觀鎖
  • Synchronized是關鍵字,内置語言實作,Lock是接口。
  • Synchronized線上程發生異常時會自動釋放鎖,是以不會發生異常死鎖。Lock異常時不會自動釋放鎖,是以需要在finally中實作釋放鎖。  

7.ThreadLocal、Volatile、Synchronized 的作用和差別

  1. ThreadLocal不是為了解決多線程通路共享變量,而是為每個線程建立一個單獨的變量副本,提供了保持對象的方法和避免參數傳遞的複雜性。
  2. volatile用volatile修飾的變量,線程在每次使用變量的時候,都會讀取變量修改後的最的值。volatile很容易被誤用,用來進行原子性操作。
  3. Synchronized 是Java利用鎖的機制自動實作的,一般有同步方法和同步代碼塊兩種使用方式。關鍵字保證了資料讀寫一緻和可見性等問題

    ThreadLocal與Synchronized差別 ThreadLocal和Synchonized都用于解決多線程并發通路,他們兩者的差別:

    synchronized是利用鎖的機制,使變量或代碼塊在某一時該隻能被一個線程通路,而ThreadLocal為每一個線程都提供了變量的副本,使得每個線程在某一時間通路到的并不是同一個對象,這樣就隔離了多個線程對資料的資料共享,而Synchronized卻正好相反,它用于在多個線程間通信時能夠獲得資料共享。一句話來說,Synchronized是為了讓多線程進行資料共享,而ThreadLocal為了讓多線程進行資料隔離。

8.同步方法和同步塊,哪個更好?

同步塊是更好的選擇,因為它不會鎖住整個對象(當然你也可以讓它鎖住整個對象)。同步方法會鎖住整個對象,哪怕這個類中有多個不相關聯的同步塊,這通常會導緻他們停止執行并需要等待獲得這個對象上的鎖。同步塊更要符合開放調用的原則,隻在需要鎖住的代碼塊鎖住相應的對象,這樣從側面來說也可以避免死鎖。

9.什麼是死鎖?如何避免死鎖?

當兩個或多個線程同時運作并且擁有對方所需要的資源時,就會等待對方釋放所持有的資源,但是都不會釋放資源,這樣就會造成堵塞,最後形成死鎖。 

如何避免線程死鎖:

我們隻要破壞産生死鎖的四個條件中的其中一個就可以了。

破壞互斥條件:這個條件我們沒有辦法破壞,因為我們用鎖本來就是想讓他們互斥的(臨界資源需要互斥通路)。

破壞請求與保持條件:一次性申請所有的資源。

破壞不剝奪條件:占用部分資源的線程進一步申請其他資源時,如果申請不到,可以主動釋放它占有的資源。

破壞循環等待條件:靠按序申請資源來預防。按某一順序申請資源,釋放資源則反序釋放。破壞循環等待條件。

10.線程池的作用是什麼,常見的參數有哪些?

線程池的作用:

  • 第一:降低資源消耗。通過重複利用已建立的線程降低線程建立和銷毀造成的消耗。
  • 第二:提高響應速度。當任務到達時,任務可以不需要等到線程建立就能立即執行。
  • 第三:提高線程的可管理性。

常見參數:

  • corePoolSize:核心線程數
  • queueCapacity:任務隊列容量(阻塞隊列)
  • maxPoolSize:最大線程數
  • keepAliveTime:線程空閑時間
  • allowCoreThreadTimeout:允許核心線程逾時