java多線程知識點總結(面試利器)
1.什麽是進程和線程
進程:程序運行資源分配的最小單位,進程內部有多個線程,會共享這個進程的資源
線程:CPU調度的最小單位,必須依賴進程而存在。
2. 新起線程方法
兩種方法:繼承類Thread
實現接口 Runnable
為什麽要類,也要接口。因為JAVA單繼承,類只能繼承一個
接口 Callable 與Runnable 區別:Callable 有返回值
3.怎麽樣才能讓Java裏的線程安全停止工作呢
線程自然終止:自然執行完或拋出未處理異常
stop(),resume(),suspend()已不建議使用,stop()會導致線程不會正確釋放資源,
java線程是協作式,而非搶占式
調用一個線程的interrupt() 方法中斷一個線程,並不是強行關閉這個線程,只是跟這個線程打個招呼,將線程的中斷標誌位置為true,線程是否中斷,由線程本身決定。
isInterrupted() 判定當前線程是否處於中斷狀態。
static方法interrupted() 判定當前線程是否處於中斷狀態,同時中斷標誌位改為false。
方法裏如果拋出InterruptedException,線程的中斷標誌位會被復位成false,如果確實是需要中斷線程,要求我們自己在catch語句塊裏再次
所有阻塞方法都會拋出InterruptedException
4.一個線程的生命周期(線程的方法)
新建線程調用start()方法進入就緒狀態,cpu分配或join()方法獲取執行權進入運行狀態,調用sleep()或wait()進入阻塞狀態,sleep時間到或調用notify,notifyAll方法進入就緒狀態,運行時還可以調用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級別的鎖,代碼簡潔,Lock:Java語言級別的鎖,獲取鎖可以被中斷,超時獲取鎖,嘗試獲取鎖,讀多寫少用讀寫鎖
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),紅黑樹則為O(logn),性能提升很大。什麽時候鏈表轉紅黑樹?當key值相等的元素形成的鏈表中元素個數超過8個的時候。
主要數據結構和關鍵變量
Node類存放實際的key和value值,hash ,next
sizeCtl:
負數:表示進行初始化或者擴容,-1表示正在初始化,-N,表示有N-1個線程正在進行擴容
正數:0 表示還沒有被初始化,>0的數,初始化或者是下一次進行擴容的閾值
TreeNode 用在紅黑樹,表示樹的節點, TreeBin是實際放在table數組中的,代表了這個紅黑樹的根。
在高並發下的情況下如何保證取得的元素是最新的?
答:用於存儲鍵值對數據的HashEntry,在設計上它的成員變量value等都是volatile類型的,這樣就保證別的線程對value值的修改,get方法可以馬上看到。
問ConcurrentHashMap如何在保證高並發下線程安全的同時實現了性能提升?
答:ConcurrentHashMap允許多個修改操作並發進行,其關鍵在於使用了鎖分離技術。它使用了多個鎖來控制對hash表的不同部分進行的修改。內部使用段(Segment)來表示這些不同的部分,每個段其實就是一個小的hash table,只要多個修改操作發生在不同的段上,它們就可以並發進行。
java多線程知識點總結(面試利器)