并发编程-13线程安全策略之两种类型的同步容器
文章目錄
- 腦圖
- 概述
- 同步容器
- 集合接口下的同步容器實(shí)現(xiàn)類
- Vector (線程安全性比ArrayList好一些,但并非絕對線程安全)
- 同步容器 線程不安全的場景
- 其他注意事項(xiàng)
- Hashtable
- Collections.synchronizedXXX方法所創(chuàng)建的同步容器
- Collections.synchronizedList
- Collections.synchronizedMap
- Collections.synchronizedSet
- 小結(jié)
- 代碼
腦圖
概述
上篇 并發(fā)編程-12線程安全策略之常見的線程不安全類講了一些常用的線程不安全的集合容器(ArrayList、HashMap、HashSet),如果有多個(gè)線程并發(fā)訪問這些集合時(shí)就會(huì)出現(xiàn)線程不安全的問題。 當(dāng)我們在使用這些容器時(shí),需要我們自己來處理線程安全的問題。 使用起來相對會(huì)有些不便,而Java在這方面提供了相應(yīng)的同步容器,我們可以在多線程情況下可以結(jié)合實(shí)際場景考慮使用這些同步容器。
同步容器
集合接口下的同步容器實(shí)現(xiàn)類
- Vector的方法都是由synchronized關(guān)鍵字保護(hù)
ctrl + o,方法左側(cè) 帶有,就可以看出是個(gè)同步方法。
- Stack繼承了Vector,并且提供了棧操作(先進(jìn)后出)
- Hashtable也是由synchronized關(guān)鍵字保護(hù)
Vector (線程安全性比ArrayList好一些,但并非絕對線程安全)
ArrayList線程不安全的例子:
https://blog.csdn.net/yangshangwei/article/details/87887613#ArrayList__121
運(yùn)行結(jié)果:
這種情況下 ,多線程 計(jì)算結(jié)果正確
同步容器 線程不安全的場景
同步容器也并不一定是絕對線程安全的,例如有兩個(gè)線程,線程A根據(jù)size的值循環(huán)執(zhí)行remove操作,而線程B根據(jù)size的值循環(huán)執(zhí)行執(zhí)行g(shù)et操作。它們都需要調(diào)用size獲取容器大小,當(dāng)循環(huán)到最后一個(gè)元素時(shí),若線程A先remove了線程B需要get的元素,那么就會(huì)報(bào)越界錯(cuò)誤
Vector中的方法都進(jìn)行了同步處理,那么一定就是線程安全的,事實(shí)上這可不一定 。來演示下
運(yùn)行結(jié)果: java.lang.ArrayIndexOutOfBoundsException
我們來分析一下:
Vector是線程安全的,為什么還會(huì)報(bào)這個(gè)錯(cuò)?對于Vector,雖然能保證每一個(gè)時(shí)刻只能有一個(gè)線程訪問它,但是不排除這種可能:
當(dāng)某個(gè)線程在某個(gè)時(shí)刻執(zhí)行這句時(shí):
for(int i=0;i<vector.size();i++){vector.get(i); }假若此時(shí)vector的size方法返回的是10,i的值為9
然后另外一個(gè)線程執(zhí)行了這句:
for(int i=0;i<vector.size();i++){vector.remove(i); }將下標(biāo)為9的元素刪除了, 那么通過get方法訪問下標(biāo)為9的元素肯定就會(huì)出問題了。
因此為了保證線程安全,必須在方法調(diào)用端做額外的同步措施
其他注意事項(xiàng)
當(dāng)我們使用foreach循環(huán)或迭代器去遍歷元素的同時(shí)又執(zhí)行刪除操作的話,即便在單線程下也會(huì)報(bào)并發(fā)修改異常.
所以在foreach循環(huán)或迭代器遍歷的過程中不能做刪除操作,若需遍歷的同時(shí)進(jìn)行刪除操作的話盡量使用for循環(huán)。實(shí)在要使用foreach循環(huán)或迭代器的話應(yīng)該先標(biāo)記要?jiǎng)h除元素的下標(biāo),然后最后再統(tǒng)一刪除. 如果使用JDK8,可以使用函數(shù)式編程
Hashtable
線程不安全的HashMap
https://blog.csdn.net/yangshangwei/article/details/87887613#HashMap__130
運(yùn)行結(jié)果:
Collections.synchronizedXXX方法所創(chuàng)建的同步容器
Collections類中提供了多個(gè)synchronizedXxx方法, 該方法返回指定集合對象對應(yīng)的同步對象,從而可以解決多線程并發(fā)訪問集合時(shí)的線程安全問題
Collections.synchronizedList
運(yùn)行結(jié)果: 線程安全
Collections.synchronizedMap
運(yùn)行結(jié)果: 線程安全
Collections.synchronizedSet
運(yùn)行結(jié)果: 線程安全
小結(jié)
同步容器是通過synchronized來實(shí)現(xiàn)同步的,所以性能較差。而且同步容器也并不是絕對線程安全的,在一些特殊情況下也會(huì)出現(xiàn)線程不安全的行為。那么有沒有更好的方式代替同步容器呢?----> 那就是**并發(fā)容器,有了并發(fā)容器后同步容器的使用也越來越少的,大部分都會(huì)優(yōu)先使用并發(fā)容器(J.U.C)**. 下篇博文我們討論下J.U.C
總之一句話,優(yōu)先使用并發(fā)容器提供的集合,而不是使用加了鎖的同步容器中的集合
代碼
https://github.com/yangshangwei/ConcurrencyMaster
總結(jié)
以上是生活随笔為你收集整理的并发编程-13线程安全策略之两种类型的同步容器的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 并发编程-12线程安全策略之常见的线程不
- 下一篇: 并发编程-14线程安全策略之并发容器(J