面試高併發,看這篇就夠了(下)
1 Thread的start方法和run方法的區別?
run方法就是普通的一個方法,程式碼執行在當前主執行緒,start會啟動一個新的執行緒,並執行run方法。
2 如何停止執行緒執行?
可以設定一個標誌位,任務定期檢查這個標記,如果標誌設定為取消則任務停止執行,但已執行部分無法停止,標誌變數最好設定為volatile。
3 普通執行緒與守護執行緒?
本質都是執行緒沒什麼區別,守護執行緒在主執行緒結束時將被拋棄,自動退出。比如垃圾回收執行緒。
4 執行緒'飢餓'死鎖
線上程池中,如果一個任務依賴其他任務,那麼可能會導致執行緒死鎖。比如在單執行緒的Executor中,一個任務將另一個任務提交到Executor中,等待這個任務的處理結果。第一個任務在等待第二個任務,而第二個任務在佇列裡等待第一個任務執行完成。
5 ThreadPoolexecutor引數配置?
corePoolSize - 池中所儲存的執行緒數,包括空閒執行緒。
maximumPoolSize - 池中允許的最大執行緒數。
keepAliveTime - 當執行緒數大於核心時,此為終止前多餘的空閒執行緒等待新任務的最長時間。
unit - keepAliveTime 引數的時間單位。
workQueue - 執行前用於保持任務的佇列。此佇列僅保持由 execute 方法提交的 Runnable 任務。
threadFactory - 執行程式建立新執行緒時使用的工廠。
handler - 由於超出執行緒範圍和佇列容量而使執行被阻塞時所使用的處理程式。
如果池中執行的執行緒小於coreSize,那麼新的請求將建立新的執行緒,如果coreSize執行緒全部忙碌,新請求將被新增到佇列,如果佇列已滿,那麼將繼續建立新執行緒,但執行緒總數<=maximumPoolSize,多餘coreSize的執行緒會在超過keepAliveTime終止。
6 執行緒池任務飽和時處理策略?
當執行緒池執行緒數已經達到最大值,注意這時佇列一定已經滿了,執行緒池已經處於飽和狀態,那麼新來的請求將會按照相對應的策略被處理。
AbortPolicy:拒絕任務,丟擲RejectedExecutionException
CallerRunsPolicy:在 execute 方法的呼叫執行緒中執行被拒絕的任務;如果執行程式已關閉,則會丟棄該任務。
DiscardPolicy:直接丟棄。
7 哲學家就餐問題?
5個哲學家一起吃午餐,圍坐在一個圓桌前,每兩個哲學家中間有一根筷子,一共有5根筷子,每個人都需要有一雙筷子才能吃到東西,哲學家們思兒思考時而進餐。當每個人都第一時間拿起左手邊的筷子,同時等待右手邊的哲學家釋放筷子的時候,就陷入了死鎖。
8 資料庫死鎖?
在執行一個事務時可能要獲取多個鎖,一直持有鎖到事務提交,如果A事務需要獲取的鎖在另一個事務B中,且B事務也在等待A事務所持有的鎖,那麼兩個事務之間就會發生死鎖。但資料庫死鎖比較少見,資料庫會加以干涉死鎖問題,犧牲一個事務使得其他事務正常執行。
9 什麼是鎖順序死鎖?
兩個執行緒試圖以不同的順序獲得相同的鎖,那麼可能發發生死鎖。比如轉賬問題,由from賬戶向to賬戶轉賬,假設每次我們先同步from物件,再同步to賬戶,然後執行轉賬操作,貌似沒什麼問題。如果這時候to賬戶同時向from賬戶轉賬,那麼兩個執行緒可能要永久等待了。

10 死鎖的避免與診斷?
如果一個執行緒最多隻能獲取一個鎖,那麼就不會發生鎖順序死鎖了。如果確實需要獲取多個鎖,鎖的順序可以按照某種規約,比如兩個資源的id值,程式按規約保證獲取鎖的順序一致。或者可以使用顯式的鎖Lock,獲取鎖的時候設定超時時間,超時後可以重新發起,以避免發生死鎖。
11 執行緒飢餓與活鎖?
當執行緒由於無法訪問需要的資源而不能繼續執行時,就是飢餓狀態。活鎖是執行緒雖然沒有阻塞,但也不能繼續執行,因為程式總是執行相同的操作,且結果都是失敗。
12 多執行緒效能問題?
使用多執行緒主要就是為了提高程式的執行效能,多執行緒可以更充分發揮系統可處理能力,從而提高系統資源利用率。但多執行緒自身同時帶來了效能開銷,執行緒的建立與銷燬,執行緒間的協調(比如加鎖、記憶體同步),執行緒排程,上下文的切換等。好的併發設計就是充分利用現有資源,儘可能使處理器忙碌起來,當然程式設計始終不能脫離業務場景。
13 記憶體同步?
在synchronized和volatile提供的可見性保證中可能會用到記憶體屏障,記憶體屏障可以重新整理快取,使快取無效。同時記憶體屏障會抑制一些編譯器優化操作,大多數操作不能被重排序。
14 jvm同步優化?
jvm可以通過優化去掉一些不必要的鎖,從而減少同步開銷。比如一個物件只能被當前執行緒訪問,其他執行緒不會與當前執行緒在這個鎖上發生同步,jvm可以鎖優化去掉同步操作。編譯器也可以進行鎖粒度粗化操作,將臨近的多個同步程式碼用一個鎖合併起來,不僅可以減少多個同步帶來的不必要的開銷,同時還能使優化器處理更大的程式碼塊,帶來進一步的優化。鎖自旋,當執行緒發生阻塞時,可能會自旋等待(不斷迴圈嘗試去獲取鎖),或者通過作業系統掛起執行緒,當然這要看鎖等待時間,來決定是否自旋。
15 降低鎖的競爭?
減少鎖的持有時間,減少鎖的請求頻率,使用帶有協調機制的獨佔鎖。具體實現可以縮小鎖的範圍,快進快出。比如只鎖同步操作程式碼塊,不要把相關非同步業務邏輯也包含到同步程式碼塊中。可以減小鎖的粒度,能對目標物件進行上鎖,就不要對操作目標物件的方法上鎖,也可以使用一些鎖分段技術的元件,比如ConcurrentHashMap。也可以使用一些非獨佔鎖,比如ReadWriteLock。