1. 程式人生 > >java多線程知識點總結(面試利器)

java多線程知識點總結(面試利器)

代碼簡潔 部分 ren hashmap cep 圖片 協作式 dex 兩個

1.什麽是進程和線程

進程:程序運行資源分配的最小單位,進程內部有多個線程,會共享這個進程的資源

線程:CPU調度的最小單位,必須依賴進程而存在。

2. 新起線程方法

兩種方法:繼承類Thread

實現接口 Runnable

為什麽要類,也要接口。因為JAVA單繼承,類只能繼承一個

接口 Callable Runnable 區別:Callable 有返回值

3.怎麽樣才能讓Java裏的線程安全停止工作呢

線程自然終止:自然執行完或拋出未處理異常

stop()resume(),suspend()已不建議使用,stop()會導致線程不會正確釋放資源,

suspend()不釋放資源容易導致死鎖。

java線程是協作式,而非搶占式

調用一個線程的interrupt() 方法中斷一個線程,並不是強行關閉這個線程,只是跟這個線程打個招呼,將線程的中斷標誌位置為true,線程是否中斷,由線程本身決定。

isInterrupted() 判定當前線程是否處於中斷狀態。

static方法interrupted() 判定當前線程是否處於中斷狀態,同時中斷標誌位改為false

方法裏如果拋出InterruptedException,線程的中斷標誌位會被復位成false,如果確實是需要中斷線程,要求我們自己在catch語句塊裏再次

調用interrupt()。

所有阻塞方法都會拋出InterruptedException

4.一個線程的生命周期(線程的方法)

新建線程調用start()方法進入就緒狀態,cpu分配或join()方法獲取執行權進入運行狀態,調用sleep()wait()進入阻塞狀態,sleep時間到或調用notifynotifyAll方法進入就緒狀態,運行時還可以調用yield方法讓步進入就緒狀態進行重新爭搶cpu

技術分享圖片

5.調用yield() sleep()wait()notify()等方法對鎖有何影響?

線程在執行yield()以後持有的鎖是不釋放的

sleep()方法被調用以後,

持有的鎖是不釋放的

調動方法之前必須要持有鎖調用了wait()方法以後,鎖就會被釋放,當wait方法返回的時候,線程會重新持有鎖

調動方法之前必須要持有鎖,調用notify()方法本身不會釋放鎖的

6.守護線程是什麽

和主線程共死,finally不能保證一定執行

start之前setDaemon(true);設置守護線程,主線程運行完,子線程也結束。

7.synchronized內置鎖

對象鎖,鎖的是類的對象實例。

類鎖 ,鎖的是每個類的的Class對象,每個類的的Class對象在一個虛擬機中只有一個,所以類鎖也只有一個。

8.volatile關鍵字

適合於只有一個線程寫,多個線程讀的場景,因為它只能確保可見性。

9.ThreadLocal

線程變量。可以理解為是個map,類型 Map<Thread,Integer>

10.CountDownLatch

作用是一線程等待其他的線程完成工作以後在執行加強版join

await用來等待,countDown負責計數器的減一

11.CyclicBarrier

讓一組線程達到某個屏障,被阻塞,一直到組內最後一個線程達到屏障時,屏障開放,所有被阻塞的線程會繼續運行CyclicBarrier(int parties)

12.Semaphore

控制同時訪問某個特定資源的線程數量,用在流量控制

13.Exchange

兩個線程間的數據交換

14.CAS的原理

CAS(Compare And Swap),指令級別保證這是一個原子操作

基本思路:如果地址V上的值和期望的值A相等,就給地址V賦給新值B,如果不是,不做任何操作。

15.Lock接口和synchronized的比較

synchronized jvm級別的鎖,代碼簡潔,LockJava語言級別的鎖,獲取鎖可以被中斷,超時獲取鎖,嘗試獲取鎖,讀多寫少用讀寫鎖

16.可重入鎖ReentrantLock所謂鎖的公平和非公平有什麽區別

如果在時間上,先對鎖進行獲取的請求,一定先被滿足,這個鎖就是公平的,不滿足,就是非公平的

非公平的效率一般來講更高

節約了從掛起(排隊)到拿鎖的時間

17.AQS是什麽

AbstractQueuedSynchronizer

實質上用雙向鏈表實現同步隊列

用AQS實現同步,首先線程獲取同步狀態失敗時,生成note節點加入同步隊列尾部(用CAS設置),判斷前驅是否為首節點,是的話嘗試獲取同步狀態,獲取成功將其設置為首節點,獲取不成功進入等待隊列,再去嘗試獲取同步狀態

競爭失敗的線程會打包成Node放到同步隊列

註:AQS實質上擁有一個同步隊列和多個等待隊列,具體對應關系如下圖所示:

技術分享圖片

上邊為同步隊列 雙向鏈表
下邊為condition等待隊列 單向鏈表
Await從同步隊列移動到等待隊列等待
Signal從等待隊列移動到同步隊列爭搶鎖

18.Concurrenthashmap實現原理

1.7及之前: ConcurrentHashMap是由Segment數組結構和HashEntry數組結構組成。Segment實際繼承自可重入鎖(ReentrantLock),在ConcurrentHashMap裏扮演鎖的角色;HashEntry則用於存儲鍵值對數據。一個ConcurrentHashMap裏包含一個Segment數組,每個Segment裏包含一個HashEntry數組,我們稱之為table,每個HashEntry是一個鏈表結構的元素。

1.8

1、 取消了segment數組,直接用table保存數據,鎖的粒度更小,減少並發沖突的概率。

2、 存儲數據時采用了鏈表+紅黑樹的形式,純鏈表的形式時間復雜度為O(n),紅黑樹則為Ologn),性能提升很大。什麽時候鏈表轉紅黑樹?當key值相等的元素形成的鏈表中元素個數超過8個的時候。

主要數據結構和關鍵變量

Node類存放實際的keyvalue,hash next

sizeCtl:

負數:表示進行初始化或者擴容,-1表示正在初始化,-N,表示有N-1個線程正在進行擴容

正數:0 表示還沒有被初始化,>0的數,初始化或者是下一次進行擴容的閾值

TreeNode 用在紅黑樹,表示樹的節點, TreeBin是實際放在table數組中的,代表了這個紅黑樹的根。

在高並發下的情況下如何保證取得的元素是最新的?

:用於存儲鍵值對數據的HashEntry,在設計上它的成員變量value等都是volatile類型的,這樣就保證別的線程對value值的修改,get方法可以馬上看到。

ConcurrentHashMap如何在保證高並發下線程安全的同時實現了性能提升?

答:ConcurrentHashMap允許多個修改操作並發進行,其關鍵在於使用了鎖分離技術。它使用了多個鎖來控制對hash表的不同部分進行的修改。內部使用段(Segment)來表示這些不同的部分,每個段其實就是一個小的hash table,只要多個修改操作發生在不同的段上,它們就可以並發進行。

java多線程知識點總結(面試利器)