ArrayList
是單線程,非線程安全,須要手動加鎖實現同步lock或sychornized;由於代碼不方便重用,CopyOnWriteArrayList
,它底層是:寫加鎖,ReentrantLock
,讀不加鎖;ReentrantLock
,基於AQS
同步,它的公平鎖和非公平鎖
,AQS
的基礎又是CAS
。區別ReentrantLock和sychornized
,和jdk關鍵字優化有關。CopyOnWriteArrayList
底層數組由volatile
修飾,保證內存可見性
,這裏涉及到重排序
,happen-before
,CAS
,內存屏障
。注意原子類型,底層就是volatile
修飾的。CAS
相似數據庫中的樂觀鎖
。CopyOnWriteArrayList
的使用場景:讀多寫少的場景,避免大量臨時數組產生
(由於每次寫的時候,須要兩個數組,寫操做併發高,致使新生代產生大量臨時數組,須要大量GC)、黑/白名單
(利用分佈式Nginx實現ip黑名單,限流,負載均衡,反爬蟲),同包下還有ConcurrentHashMap
,7與8的Hashmap和ConcurrentHashMap區別
。保證思路連續性java
ConcurrentModificationException併發修改異常
,產生於iterator迭代遍歷ArrayList,刪除一個元素,產生異常,for/foreach也是,expectedModCount
表示修改次數指望值,初始值與modCount
相等,可是修改集合成員時,modCount
會變化,當二者不相等是,拋出這個異常,因此須要移除時不能使用list.remove(xxx),而是使用iterator.remove(),由於這個方法會設置那兩個參數相等。
說出在什麼場景下出現異常
(發現問題能力)
、說出異常緣由(分析問題能力)
、說出解決方案(解決問題能力)
、對一個小問題的擴展和延伸(總結問題能力)
示例:發現問題——ArrayList遍歷出現異常、分析問題——找到源碼緣由、解決問題——使用迭代器remove方法能夠避免、總結問題——多線程場景下迭代器remove方法產生問題引出併發容器
引出CopyOnWriteArrayList,在查看mysql驅動程序類的時候Driver中發現的
mysql
lock.lock(); //加鎖,保證線程安全 Arrays.copyOf(); //拷貝出新數組 private volatile transient Object[] array; lock.unlock(); //finally中解鎖,防止出現異常致使鎖不釋放 /** * 大體流程都是 先lock一下保證線程安全,拷貝出新數組,操做,修改原數組引用指向新數組,unlock解鎖 * 高併發讀請求,走的是舊數組。 */
延伸至 volatile關鍵字
volatile是保證線程內存可見性 ,區別於加鎖。
volatile經過JVM底層一些指令,例如:happen-before規則,內存屏障等技術,保證cpu0放入到memory內存中,執行jvm中指令,強制硬件層面上,其餘cpu的cache緩存爲無效狀態,強制從memory中獲取新值,放到各自的緩存中進行計算。"大體是清其餘cpu緩存,再從新拿緩存"
web
延伸至 CAS原子類型操做
CAS(Compare and Swap)
原子類型:保證操做都是線程安全的。
例如:AtomicInteger 底層有一個 private volatile int value; //實際就是int + volatile修飾面試
內存值V
、舊的預期值A
、要修改的新值B
當且僅當預期值A和內存值V相同時,將內存值V修改成B,不然什麼都不作。
重入鎖
:同一時間,只有一個線程可使用臨界資源;公平鎖
是如果同一線程競爭資源,是能夠加上鎖的,先來後到;非公平鎖
,後續線程沒有按照隊列形式來拿到鎖。在多線程高併發環境下,多線程競爭鎖,有一個競爭成功加上鎖,成功的線程直接執行方法邏輯;
加鎖失敗,生成阻塞隊列
,存放全部等待線程,等待獲取釋放鎖後的使用權;當前一個使用者釋放鎖, 隊列會喚醒一個線程去競爭資源加鎖,以達到線程安全的效果;成功就加鎖,失敗就再回到阻塞隊列。sql
volatile是輕量級的synchronized。鎖提供了兩種特性,互斥和可見性。所以在保證多線程讀寫時數據的一致性,可使用同步即synchronized關鍵字和可見性即volatile。數據庫
1.volatile數組
可見性的意思即當一個線程修改了共享變量時,另外一個線程也能讀取到這個最新的數值。緩存
對於volatile修飾的變量在進行寫操做時,處理器不會直接和內存通訊,會先寫入到緩存中。在這個寫入緩存的過程當中,用到緩存一致性確保修改的原子性。當緩存回寫到內存中時會致使其餘處理器對此變量的緩存無效,會從新讀取此變量的值。安全
2.synchronized和volatile的區別多線程
1)volatile本質是在告訴jvm當前變量在寄存器中的值是不肯定的,須要從主存中讀取,synchronized則是鎖定當前變量,只有當前線程能夠訪問該變量,其餘線程被阻塞住.
2)volatile僅能使用在變量級別,synchronized則可使用在變量,方法.
3)volatile僅能實現變量的修改可見性,而synchronized則能夠保證變量的修改可見性和原子性.
4)volatile不會形成線程的阻塞,而synchronized可能會形成線程的阻塞.