大家好,我是冰河~~
說實話,在實際的工作過程中,我在使用JDK中的并發容器時,确實踩過不少坑。為了讓小夥伴們更好的消化這些知識,今天,首先和小夥伴們分享下使用同步容器時需要注意哪些問題,後續再為大家分享使用并發容器時需要注意哪些問題,以便大家在實際工作過程中盡量少走彎路。
相信很多小夥伴都知道,并發程式設計一直都是一個難點,不僅僅是Java語言,其他程式設計語言也是如此。說它難,不隻是并發程式設計需要我們掌握的知識點比較繁雜,包括:作業系統知識、系統排程知識、CPU、時間片、記憶體、同步、異步、鎖、重排序、多線程、線程池、悲觀鎖、樂觀鎖等等一系列知識。
而且并發程式設計還可能會導緻線上生産環境出現一系列的詭異問題,并且這些問題重制幾率小,排查困難,需要深入了解并發程式設計的相關知識才能很好的解決遇到的問題。
如何更好的學習高并發程式設計,不用着急,關注冰河的CSDN部落格,訂閱【精通高并發系列】就好啦,我們一起進階,一起吃透高并發程式設計。
如果文章對你有點幫助,小夥伴們點贊、收藏、關注、評論、分享,走一波哇~~
啰嗦了這麼多,接下來,我們開始今天的主題,為大家分享下在使用JDK中的同步容器時,應該盡量避免哪些坑。
在JDK中,總體上可以将容器分為同步容器和并發容器。

同步容器一般指的是JDK1.5版本之前的線程安全的容器,同步容器有個最大的問題,就是性能差,容器中的所有方法都是用synchronized保證互斥,串行度太高。在JDK1.5之後提供了性能更高的線程安全的容器,我們稱之為并發容器。
無論是同步容器還是并發容器,都可以将其分為四個大類,分别為:List、Set、Map和Queue,如下所示。
接下來,我們就簡單聊聊使用JDK中的同步容器時,究竟要注意避免哪些坑。
在Java中,容器可以分為四大類:List、Set、Map和Queue,但是在這些容器中,有些容器并不是線程安全的,例如我們經常使用的ArrayList、HashSet、HashMap等等就不是線程安全的容器。
那麼,根據我們在【精通高并發系列】專欄學習的并發程式設計知識,如何将一個不是線程安全的容器變成線程安全的呢? 相信有很多小夥伴都能夠想到一個辦法,那就是把非線程安全的容器的方法都加上synchronized鎖,使這些方法的通路都變成同步的。
沒錯,這确實是一種解決方案,例如,我們自定義一個 <code>CustomSafeHashMap</code>類,内部維護着一個<code>HashMap</code>,外界對<code>HashMap</code>的通路都加上了synchronized鎖,以此來保證方法的原子性,例如下面的僞代碼所示。
看到這裡,一些小夥伴可能會想:是不是所有的非線程安全的容器類都可以通過為方法添加synchronized鎖來保證方法的原子性,進而使容器變得安全呢?
是的,我們可以通過為非線程安全的容器方法添加synchronized鎖來解決容器的線程安全問題。其實,在JDK中也是這麼做的。例如,在JDK中提供了線程安全的List、Set和Map,它們都是通過synchronized鎖保證線程安全的。
例如,我們可以通過如下方式建立線程安全的List、Set和Map。
那麼,說了這麼多,同步容器有哪些坑呢?
在使用同步容器時需要注意的是,在并發程式設計中,組合操作要時刻注意競态條件,例如下面的代碼。
其中,<code>putIfNotExists()</code>方法就包含組合操作。在高并發環境中,存在組合操作的方法可能就會存在競态條件。
也就是說,在并發程式設計中,即使每個操作都能保證原子性,也不能保證組合操作的原子性。
一個容易被人忽略的坑就是使用疊代器周遊容器,對容器中的每個元素調用一個方法,這就存在了并發問題,這些組合操作不具備原子性。
例如下面的代碼,通過疊代器周遊同步List,對List集合中的每個元素調用format()方法。
此時,會存在并發問題,這些組合操作并不具備原子性。
如何解決這個問題呢?一個很簡單的方式就是鎖住list集合,如下所示。
這裡,為何鎖住list集合就能夠解決并發問題呢?
這是因為在Collections類中,其内部的包裝類的公共方法鎖住的對象是this,其實就是上面代碼中的list,是以,我們對list加鎖後,就能夠保證線程的安全性了。
在Java中,同步容器一般都是基于synchronized鎖實作的,有些是通過包裝類實作的,例如List、Set、Map等。有些不是通過包裝類實作的,例如Vector、Stack、HashTable等。
對于這些容器的周遊操作,一定要為容器添加互斥鎖保證整體的原子性。
如果你想進大廠,想升職加薪,或者對自己現有的工作比較迷茫,都可以私信我交流,希望我的一些經曆能夠幫助到大家~~
好了,今天就到這兒吧,小夥伴們點贊、收藏、評論,一鍵三連走起呀,我是冰河,我們下期見~~