雲析面試講解公開課(如何提升offer命中率)2018-12-23
集合相關
- 集合相關異常,以及使用各集合間的優缺點?
- 臨時解決方案:百度、諮詢同事、快速界解決問題,避免影響專案進度;
- 解決後的問題反思:
ArrayList
是單執行緒,非執行緒安全,需要手動加鎖實現同步lock或sychornized;因為程式碼不方便重用,CopyOnWriteArrayList
,它底層是:寫加鎖,ReentrantLock
,讀不加鎖;ReentrantLock
,基於AQS
同步,它的公平鎖和非公平鎖
,AQS
的基礎又是CAS
。區別ReentrantLock和sychornized
CopyOnWriteArrayList
底層陣列由volatile
修飾,保證記憶體可見性
,這裡涉及到重排序
,happen-before
,CAS
,記憶體屏障
。注意原子型別,底層就是volatile
修飾的。CAS
類似資料庫中的樂觀鎖
。
CopyOnWriteArrayList
的使用場景:讀多寫少的場景,避免大量臨時陣列產生
(因為每次寫的時候,需要兩個陣列,寫操作併發高,導致新生代產生大量臨時陣列,需要大量GC)、黑/白名單
(利用分散式Nginx實現ip黑名單,限流,負載均衡,反爬蟲),同包下還有ConcurrentHashMap
,7與8的Hashmap和ConcurrentHashMap區別
保證思路連續性
- 一些常見問題:ArrayList的坑、集合優缺點、集合中常見異常、ArrayList能不能在多執行緒中使用
ConcurrentModificationException併發修改異常
,產生於iterator迭代遍歷ArrayList,刪除一個元素,產生異常,for/foreach也是,expectedModCount
表示修改次數期望值,初始值與modCount
相等,但是修改集合成員時,modCount
會變化,當兩者不相等是,丟擲這個異常,所以需要移除時不能使用list.remove(xxx),而是使用iterator.remove(),因為這個方法會設定那兩個引數相等。
說出在什麼場景下出現異常
(發現問題能力)
、說出異常原因(分析問題能力)
、說出解決方案(解決問題能力)
、對一個小問題的擴充套件和延伸(總結問題能力)
示例:發現問題——ArrayList遍歷出現異常、分析問題——找到原始碼原因、解決問題——使用迭代器remove方法可以避免、總結問題——多執行緒場景下迭代器remove方法產生問題引出併發容器
引出CopyOnWriteArrayList,在檢視mysql驅動程式類的時候Driver中發現的
- 專案中的例子:
- CopyOnWriteArrayList原理
- java.util.concurrent包、字面意思write寫操作需要copy、任何可變操作(add,set,remove等操作)伴隨複製動作
- 原始碼淺析
新增元素——add(E e)
lock.lock(); //加鎖,保證執行緒安全
Arrays.copyOf(); //拷貝出新陣列 private volatile transient Object[] array;
lock.unlock(); //finally中解鎖,防止出現異常導致鎖不釋放
/**
* 大致流程都是 先lock一下保證執行緒安全,拷貝出新陣列,操作,修改原陣列引用指向新陣列,unlock解鎖
* 高併發讀請求,走的是舊陣列。
*/
- CopyOnWriteArrayList面試關鍵點
- 寫時複製機制
- 寫操作加鎖/解鎖
- 讀操作不需要幾所
- 體現讀寫分離的思想
- 體現最終一致性思想
- 在JDBC驅動程式原始碼中廣泛使用
- 使用場景:讀多寫少場景——黑名單、白名單、商品類目
-
延伸至 volatile關鍵字
volatile是保證執行緒記憶體可見性 ,區別於加鎖。
volatile通過JVM底層一些指令,例如:happen-before規則,記憶體屏障等技術,保證cpu0放入到memory記憶體中,執行jvm中指令,強制硬體層面上,其他cpu的cache快取為無效狀態,強制從memory中獲取新值,放到各自的快取中進行計算。"大致是清其他cpu快取,再重新拿快取"
-
延伸至 CAS原子型別操作
CAS(Compare and Swap)
原子型別:保證操作都是執行緒安全的。
例如:AtomicInteger 底層有一個 private volatile int value; //實際就是int + volatile修飾
- CAS有三個運算元
記憶體值V
、舊的預期值A
、要修改的新值B
當且僅當預期值A和記憶體值V相同時,將記憶體值V修改為B,否則什麼都不做。
- 延伸至 樂觀鎖
- 延伸至 鎖
Synchronized是依賴於JVM實現的(作業系統實現)、ReentrantLock是JDK實現的(開發者實現)、兩者效能相當
- 常見的ReentrantLock
重入鎖
:同一時間,只有一個執行緒可以使用臨界資源;公平鎖
是若是同一執行緒競爭資源,是可以加上鎖的,先來後到;非公平鎖
,後續執行緒沒有按照佇列形式來拿到鎖。
在多執行緒高併發環境下,多執行緒競爭鎖,有一個競爭成功加上鎖,成功的執行緒直接執行方法邏輯;
加鎖失敗,生成阻塞佇列
,存放所有等待執行緒,等待獲取釋放鎖後的使用權;當前一個使用者釋放鎖, 佇列會喚醒一個執行緒去競爭資源加鎖,以達到執行緒安全的效果;成功就加鎖,失敗就再回到阻塞佇列。
- sychornized 和 volatile關鍵字
volatile是輕量級的synchronized。鎖提供了兩種特性,互斥和可見性。因此在保證多執行緒讀寫時資料的一致性,可以使用同步即synchronized關鍵字和可見性即volatile。
1.volatile
可見性的意思即當一個執行緒修改了共享變數時,另一個執行緒也能讀取到這個最新的數值。
對於volatile修飾的變數在進行寫操作時,處理器不會直接和記憶體通訊,會先寫入到快取中。在這個寫入快取的過程中,用到快取一致性確保修改的原子性。當快取回寫到記憶體中時會導致其他處理器對此變數的快取無效,會重新讀取此變數的值。
2.synchronized和volatile的區別
1)volatile本質是在告訴jvm當前變數在暫存器中的值是不確定的,需要從主存中讀取,synchronized則是鎖定當前變數,只有當前執行緒可以訪問該變數,其他執行緒被阻塞住.
2)volatile僅能使用在變數級別,synchronized則可以使用在變數,方法.
3)volatile僅能實現變數的修改可見性,而synchronized則可以保證變數的修改可見性和原子性.
4)volatile不會造成執行緒的阻塞,而synchronized可能會造成執行緒的阻塞.