多線程面試問題,背完去面試 (面試篇二)

  最近把多線程又看了一遍,已經是第三次系統的看了,發現多線程跟JVM聯繫還是很大的。剛好就結合在一起總結了一下。聲明這篇博客是總結性的,你有一定的基礎,幫你捋一遍多線程的重要知識點。


1. 我感覺多線程跟JVM本身還是有很多相似之處的。我就將兩者結合起來看了。進程由多個線程組成,每個線程又可以在虛擬機棧中開闢多個棧幀空間。買個棧幀由局部變量,操作數指針表,動態鏈接堆對象的地址,返回地址,附加信息組成。保證多線程安全就是保證數據的原子性,可見性和有序性。常見的總線加鎖(降低CPU的吞吐量),或者實現MESI(緩存上的一致性協議)。

2. 多線程下每個線程處理一個變量,該變量存放在工作內存區域,會將變量讀取到私有空間,在私有空間處理完成之後,再返給公有空間,所以多線程下數據不能保證正確性。

3. 首先是Synchronized關鍵字,可以用來修改代碼塊和方法。它的原理是鎖住你需要的對象(類由多個對象組成),一次只允許一個線程對其進行操作,重量級的鎖。利用jclasslib查看,synchronized鎖方法塊的時候,使用了monitorenter 和 monitorexit,針對每個對象都有個鎖計數器,來一個加一個,釋放一個減一個,用的時候容器產生死鎖。當鎖住方法的時候,就有access flags的標誌位。類由三部分組成對象頭區域,實例數據區域,對齊填充區域。對象頭區域又包括Markdown專門用來記錄鎖的標誌位佔8字節,其中32位用來記錄鎖的相關信息。類型指針(指針壓縮部分),數組長度。

4. 因爲Synchronized是重量級的鎖,所以在Markdown部分改進了鎖,有了偏向鎖,設置計算器。然後輕量級的鎖,自旋鎖。鎖消除(JIT即時編譯)。鎖可以升級,但是不會降級。Synchronized是利用互斥性來保證的線程安全的。保證原子性和可見性。

5. volatile保證了多線程的可見性和有序性。Volatile不能保證原子性。多個線程操作數據的時候,還是會出問題。彙編層反編譯可以看出volatile對變量使用了lock變量。Volatile底層模擬了MESI協議,當線程寫操作的操作,將變量的CACHE_LINE置爲無效,別的線程只能從主內存中獲取。Volatile修飾的上下文變量無法指令重排序(JS的預編譯)。輕量級鎖,但是無法保證原子性。相比於Synchronized還不會阻塞。

6.對於以上的缺點,改進的方法CAS和AQS理論。CAS(CompareAndSwap)(V,E,N)比較交換,底層就一句話的,調用了unsafe的vm方法,直接是底層的C++方法cxmnchg。如果CPU指令過快,AtomicStampedReference排序。樂觀鎖和悲觀鎖,樂觀鎖,mysql的version字段。

7.CAS不適用於大量線程的時候,因此AQS(AbstractQueuedSynchronized 同步發生器)。自己extends AQS,然後implements Lock接口,就是一個簡單的ReentrantLock()。LOCK內存是CLH同步雙端隊列,爲了減少線程間切換的開銷,引入自旋鎖。會等待5~10次,公平,非公平搶佔資源,FIFO隊列。ReentranLock又改進了讀寫分離鎖。

8. 自己也可以管理線程池,但是麻煩,因爲涉及GC,Executors改進了finalize()方法,利用SecurityManager()進行管理,線程池只能釋放,不能被回收。ThreadPoolExecutor()裏面的參數都是比較重要的,定義了線程池的基本信息,尤其有一個Blocking 阻塞隊列的方法,無界隊列給cached用的。

線程的生命週期:Running Shutdown Stop tidying isterminated

線程池的生命週期:開始(Executors有了)。

9.幾個工具類  

CountDownLatch 倒計時。CyclicBarrier 一起跑步。

Semaphore 類似FixedThreadPools

集合類 ConcurrentLinkedDeque(非阻塞)  LinkedBlockingDeque(阻塞)。

10. 死鎖產生的四個必要條件

  互斥  請求與保持  非剝奪  循環等待


很多不足之處,希望大家指出。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章