8.互聯網大廠高頻面試題-arraylist線程不安全

集合類不安全之併發修改異常

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
新建對象的過程中,底層新建了一個初始大小爲10的obj數組。
在這裏插入圖片描述
size是數組裏面的元素。
在這裏插入圖片描述
在這裏插入圖片描述
add方法的源碼:
在這裏插入圖片描述
添加的時候先確認內部空間,讓其加一。函數源碼如下:
在這裏插入圖片描述
如果是默認的數組,沒寫大小,內部空間就是10,minCapacity是size,size是全局變量,jvm賦初始值0,加一之後就是1。default_capacity是全局靜態變量,如下:
在這裏插入圖片描述
如果增加到了一定程度,需要通過ensureExplicitcapacity方法擴容。
在這裏插入圖片描述
擴充原來長度的一半。
在這裏插入圖片描述
arraylist線程不安全的例子,寫一個。以add方法爲例,演示線程不安全,因爲add方法的源代碼沒有加鎖。

在這裏插入圖片描述
結果2:
在這裏插入圖片描述
數量上不對了,內容上不對了,但是,沒有報錯!
線程改爲30個之後,出現了經典的併發修改問題:
在這裏插入圖片描述
發生了JUC的併發修改異常,這是做併發項目經常遇到的。
作爲一個程序員,解決問題的框架是4步:
在這裏插入圖片描述
發現故障現象,分析導致原因,提出解決方案,總結最佳實踐(優化建議)。
故障現象就是那個異常了,導致原因就是arraylist不能支持併發,會有多線程的安全問題。
建立自己的故障筆記。只會擼代碼走不遠。天下武藝,沒有高低之分,只有習武之人,有強弱之別。
arraylist沒有加sync同步關鍵字,報了這個錯,換成線程安全的vector,它的add方法加了sync關鍵字,結果就是:
在這裏插入圖片描述
沒有出現異常。但是加鎖,會讓併發性急劇下降!
arraylist是jdk1.2版本出現的,vector是1.1版本。
我們可以提出方案是vector解決,就不會報異常了,但是不是最佳實踐。
可以使用Collections包裝類,來包裝list爲同步的,兼容併發。
在這裏插入圖片描述
也是可以解決的,這是方案二,但是底層還是加了sync關鍵字。性能下降是硬傷。
在這裏插入圖片描述

在這裏插入圖片描述

方案三:copyOnWriteArrayList,俗稱寫時複製。
在這裏插入圖片描述
先看運行效果,是可以解決問題的。
在這裏插入圖片描述
到此,不要只是會用,要明白底層原理!
筆試,過關說明你沒有喪失學習能力,不一定能直接幹活!
底層解析:
在這裏插入圖片描述

存儲數據的數組是volatile修飾的,線程可見,禁止重排。在高併發場景裏面,重要的核心變量都需要加volatile。
add方法解析:
在這裏插入圖片描述
源代碼加了可重入鎖(reentrantlock),先對原先的數組進行賦值,得到備份數組,然後對備份數組操作,此時其他線程可以併發讀取,不影響,對備份數組操作完了之後,此處爲添加一個數據,再把真實數組的引用指向備份數組,實現數據的更新,替換掉舊的數組。最後記得釋放鎖。

出現併發修改異常的原因解讀:
類似簽到,沒有順序,你爭我搶,就可能在紙上劃一長道。
在這裏插入圖片描述
陽哥筆記:
在這裏插入圖片描述

集合類不安全之set

hashset線程不安全代碼展示

在這裏插入圖片描述
同樣的配方,同樣的味道。

解決方案

最直接的使用collections工具類,把hashset包裝起來。
還有JUC寫時複製set。
在這裏插入圖片描述
打開它的源碼,你會發現,兩套臺子,一套班子,底層是用的寫時複製arraylist。
在這裏插入圖片描述
hashset的底層數據結構就是hashmap,只保留key。
在這裏插入圖片描述
創建了一個初始大小是16,負載因子0.75的hashmap。
add方法hashset有1個參數,但是hashmap是有兩個值的數據結構k-v。
在這裏插入圖片描述
hashset確實只用到了hashmap的k部分,v部分是一個obj常量。所以add方法只有一個參數即可。
在這裏插入圖片描述

集合類不安全值map

併發更新異常代碼:
在這裏插入圖片描述

解決方案-併發map

在這裏插入圖片描述
用法跟hashmap沒有區別。
在這裏插入圖片描述
同樣的,用collections工具類也可以。
在這裏插入圖片描述

transferValue醒腦小練習

題目

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
運行結果:
在這裏插入圖片描述
需要弄明白這些變量再jvm裏面的位置和變量作用域。
棧管運行,堆管存儲。第一個age,是存在棧的方法裏,值傳遞,相當於傳遞了複印件。基本類型傳遞複印件。
在這裏插入圖片描述
person的屬性改變,改變堆裏的的內容,傳遞的是引用,兩個引用指向同一塊地址,所以修改的是同一個對象。
在這裏插入圖片描述
string類型的變量,是因爲string分兩種,一種是new出來的,一種是直接等於字符串的。
在這裏插入圖片描述
因爲string本身的特殊性,更改的時候,會去池子裏找有沒有這個xxx,沒有就新建,這樣方法裏面的指針,和string原來的指針就對不上了。

在這裏插入圖片描述

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