内射老阿姨1区2区3区4区_久久精品人人做人人爽电影蜜月_久久国产精品亚洲77777_99精品又大又爽又粗少妇毛片

Java多線程理解:線程安全的集合對(duì)象-創(chuàng)新互聯(lián)

1、概念介紹

你所需要的網(wǎng)站建設(shè)服務(wù),我們均能行業(yè)靠前的水平為你提供.標(biāo)準(zhǔn)是產(chǎn)品質(zhì)量的保證,主要從事做網(wǎng)站、網(wǎng)站建設(shè)、企業(yè)網(wǎng)站建設(shè)、手機(jī)網(wǎng)站開發(fā)、網(wǎng)頁設(shè)計(jì)、成都品牌網(wǎng)站建設(shè)、網(wǎng)頁制作、做網(wǎng)站、建網(wǎng)站。成都創(chuàng)新互聯(lián)公司擁有實(shí)力堅(jiān)強(qiáng)的技術(shù)研發(fā)團(tuán)隊(duì)及素養(yǎng)的視覺設(shè)計(jì)專才。
  • 線程安全就是多線程訪問時(shí),采用了加鎖機(jī)制,當(dāng)一個(gè)線程訪問該類的某個(gè)數(shù)據(jù)時(shí),進(jìn)行保護(hù),其他線程不能進(jìn)行訪問直到該線程讀取完,其他線程才可使用。不會(huì)出現(xiàn)數(shù)據(jù)不一致或者數(shù)據(jù)污染。

  • 線程不安全就是不提供數(shù)據(jù)訪問保護(hù),多線程先后更改數(shù)據(jù)會(huì)產(chǎn)生數(shù)據(jù)不一致或者數(shù)據(jù)污染的情況。

  • 一般使用synchronized關(guān)鍵字加鎖同步控制,來解決線程不安全問題。

2、線程安全的集合對(duì)象

  • ArrayList線程不安全,Vector線程安全;

  • HashMap線程不安全,HashTable線程安全;

  • StringBuilder線程不安全,StringBuffer線程安全。

3、代碼測試

  • ArrayList線程不安全:
    在主線程中新建100個(gè)子線程,分別向ArrayList中添加100個(gè)元素,最后打印ArrayList的size。

public?class?Test?{??public?static?void?main(String?[]?args){??????//?用來測試的List??
??????List<String>?data?=?new?ArrayList<>();??????//?用來讓主線程等待100個(gè)子線程執(zhí)行完畢??
??????CountDownLatch?countDownLatch?=?new?CountDownLatch(100);??????//?啟動(dòng)100個(gè)子線程??
??????for(int?i=0;i<100;i++){
??????????SampleTask?task?=?new?SampleTask(data,countDownLatch);
??????????Thread?thread?=?new?Thread(task);
??????????thread.start();
??????}??????try{??????????//?主線程等待所有子線程執(zhí)行完成,再向下執(zhí)行??
??????????countDownLatch.await();
??????}catch?(InterruptedException?e){??
??????????e.printStackTrace();??
??????}?
??????//?List的size??
??????System.out.println(data.size());
??}
}class?SampleTask?implements?Runnable?{
????CountDownLatch?countDownLatch;
????List<String>?data;????public?SampleTask(List<String>?data,CountDownLatch?countDownLatch){????????this.data?=?data;????????this.countDownLatch?=?countDownLatch;
????}????@Override
????public?void?run()?{????????//?每個(gè)線程向List中添加100個(gè)元素??
????????for(int?i?=?0;?i?<?100;?i++)??
????????{??
????????????data.add("1");
????????}??
????????//?完成一個(gè)子線程??
????????countDownLatch.countDown();
????}
}

7次測試輸出():

99981000010000ArrayIndexOutOfBoundsException1000099679936
  • Vector線程安全:
    在主線程中新建100個(gè)子線程,分別向Vector中添加100個(gè)元素,最后打印Vector的size。

public?class?Test?{??public?static?void?main(String?[]?args){??????//?用來測試的List??
??????List<String>?data?=?new?Vector<>();??????//?用來讓主線程等待100個(gè)子線程執(zhí)行完畢??
??????CountDownLatch?countDownLatch?=?new?CountDownLatch(100);??????//?啟動(dòng)100個(gè)子線程??
??????for(int?i=0;i<100;i++){
??????????SampleTask?task?=?new?SampleTask(data,countDownLatch);
??????????Thread?thread?=?new?Thread(task);
??????????thread.start();
??????}??????try{??????????//?主線程等待所有子線程執(zhí)行完成,再向下執(zhí)行??
??????????countDownLatch.await();
??????}catch?(InterruptedException?e){??
??????????e.printStackTrace();??
??????}?
??????//?List的size??
??????System.out.println(data.size());
??}
}class?SampleTask?implements?Runnable?{
????CountDownLatch?countDownLatch;
????List<String>?data;????public?SampleTask(List<String>?data,CountDownLatch?countDownLatch){????????this.data?=?data;????????this.countDownLatch?=?countDownLatch;
????}????@Override
????public?void?run()?{????????//?每個(gè)線程向List中添加100個(gè)元素??
????????for(int?i?=?0;?i?<?100;?i++)??
????????{??
????????????data.add("1");
????????}??
????????//?完成一個(gè)子線程??
????????countDownLatch.countDown();
????}
}

7次測試輸出():

10000100001000010000100001000010000
  • 使用synchronized關(guān)鍵字來同步ArrayList:

public?class?Test?{??public?static?void?main(String?[]?args){??????//?用來測試的List??
??????List<String>?data?=?new?ArrayList<>();??????//?用來讓主線程等待100個(gè)子線程執(zhí)行完畢??
??????CountDownLatch?countDownLatch?=?new?CountDownLatch(100);??????//?啟動(dòng)100個(gè)子線程??
??????for(int?i=0;i<100;i++){
??????????SampleTask?task?=?new?SampleTask(data,countDownLatch);
??????????Thread?thread?=?new?Thread(task);
??????????thread.start();
??????}??????try{??????????//?主線程等待所有子線程執(zhí)行完成,再向下執(zhí)行??
??????????countDownLatch.await();
??????}catch?(InterruptedException?e){??
??????????e.printStackTrace();??
??????}?
??????//?List的size??
??????System.out.println(data.size());
??}
}class?SampleTask?implements?Runnable?{
????CountDownLatch?countDownLatch;
????List<String>?data;????public?SampleTask(List<String>?data,CountDownLatch?countDownLatch){????????this.data?=?data;????????this.countDownLatch?=?countDownLatch;
????}????@Override
????public?void?run()?{????????//?每個(gè)線程向List中添加100個(gè)元素??
????????for(int?i?=?0;?i?<?100;?i++)??
????????{??
????????????synchronized(data){
????????????????data.add("1");
????????????}
????????}??
????????//?完成一個(gè)子線程??
????????countDownLatch.countDown();
????}
}

7次測試輸出():

10000100001000010000100001000010000

3、原因分析

  • ArrayList在添加一個(gè)元素的時(shí)候,它會(huì)有兩步來完成:1. 在 Items[Size] 的位置存放此元素;2. 增大 Size 的值。
    在單線程運(yùn)行的情況下,如果 Size = 0,添加一個(gè)元素后,此元素在位置 0,而且 Size=1;
    而如果是在多線程情況下,比如有兩個(gè)線程,線程 A 先將元素1存放在位置 0。但是此時(shí) CPU 調(diào)度線程A暫停,線程 B 得到運(yùn)行的機(jī)會(huì)。線程B向此 ArrayList 添加元素2,因?yàn)榇藭r(shí) Size 仍然等于 0 (注意,我們假設(shè)的是添加一個(gè)元素是要兩個(gè)步驟,而線程A僅僅完成了步驟1),所以線程B也將元素存放在位置0。然后線程A和線程B都繼續(xù)運(yùn)行,都增加 Size 的值,結(jié)果Size都等于1。
    最后,ArrayList中期望的元素應(yīng)該有2個(gè),而實(shí)際元素是在0位置,造成丟失元素,故Size 等于1。導(dǎo)致“線程不安全”。
    ArrayList源碼:

@Override?public?boolean?add(E?object)?{
????????Object[]?a?=?array;????????int?s?=?size;????????if?(s?==?a.length)?{
????????????Object[]?newArray?=?new?Object[s?+
????????????????????(s?<?(MIN_CAPACITY_INCREMENT?/?2)??
?????????????????????MIN_CAPACITY_INCREMENT?:?s?>>?1)];
????????????System.arraycopy(a,?0,?newArray,?0,?s);
????????????array?=?a?=?newArray;
????????}
????????a[s]?=?object;
????????size?=?s?+?1;
????????modCount++;????????return?true;
????}
  • Vector的所有操作方法都被同步了,既然被同步了,多個(gè)線程就不可能同時(shí)訪問vector中的數(shù)據(jù),只能一個(gè)一個(gè)地訪問,所以不會(huì)出現(xiàn)數(shù)據(jù)混亂的情況,所以是線程安全的。
    Vector源碼:

@Override
????public?synchronized?boolean?add(E?object)?{????????if?(elementCount?==?elementData.length)?{
????????????growByOne();
????????}
????????elementData[elementCount++]?=?object;
????????modCount++;????????return?true;
????}

4、線程安全的集合并不安全

分析以下場景:

synchronized(map){
Object?value?=?map.get(key);if(value?==?null)
{
????value?=?new?Object();
????map.put(key,value);
}return?value;}

由于線程安全的集合對(duì)象是基于單個(gè)方法的同步,所以即使map是線程安全的,也會(huì)產(chǎn)生不同步現(xiàn)象。
在非單個(gè)方法的場景下,我們?nèi)匀恍枰褂胹ynchronized加鎖才能保證對(duì)象的同步。

代碼測試:

public?class?Test?{??public?static?void?main(String?[]?args){??????//?用來測試的List??
??????List<String>?data?=?new?Vector<>();??????//?用來讓主線程等待100個(gè)子線程執(zhí)行完畢??
??????CountDownLatch?countDownLatch?=?new?CountDownLatch(100);??????//?啟動(dòng)100個(gè)子線程??
??????for(int?i=0;i<1000;i++){
??????????SampleTask?task?=?new?SampleTask(data,countDownLatch);
??????????Thread?thread?=?new?Thread(task);
??????????thread.start();
??????}??????try{??????????//?主線程等待所有子線程執(zhí)行完成,再向下執(zhí)行??
??????????countDownLatch.await();
??????}catch?(InterruptedException?e){??
??????????e.printStackTrace();??
??????}?
??????//?List的size??
??????System.out.println(data.size());
??}
}class?SampleTask?implements?Runnable?{
????CountDownLatch?countDownLatch;
????List<String>?data;????public?SampleTask(List<String>?data,CountDownLatch?countDownLatch){????????this.data?=?data;????????this.countDownLatch?=?countDownLatch;
????}????@Override
????public?void?run()?{????????//?每個(gè)線程向List中添加100個(gè)元素??
????????int?size?=?data.size();
????????data.add(size,"1");?
????????//?完成一個(gè)子線程??
????????countDownLatch.countDown();
????}
}
997
993
995
996
997
998
997

5、總結(jié)

  • 如何取舍
    線程安全必須要使用synchronized關(guān)鍵字來同步控制,所以會(huì)導(dǎo)致性能的降低。
    當(dāng)不需要線程安全時(shí),可以選擇ArrayList,避免方法同步產(chǎn)生的開銷;
    當(dāng)多個(gè)線程操作同一個(gè)對(duì)象時(shí),可以選擇線程安全的Vector;

  • 線程不安全!=不安全
    有人在使用過程中有一個(gè)不正確的觀點(diǎn):我的程序是多線程的,不能使用ArrayList要使用Vector,這樣才安全。
    線程不安全并不是多線程環(huán)境下就不能使用
    注意線程不安全條件:多線程操作同一個(gè)對(duì)象。比如上述代碼就是在多個(gè)線程操作同一個(gè)ArrayList對(duì)象。
    如果每個(gè)線程中new一個(gè)ArrayList,而這個(gè)ArrayList只在這一個(gè)線程中使用,那么是沒問題的。

  • 線程‘安全’的集合對(duì)象
    較復(fù)雜的操作下,線程安全的集合對(duì)象也無法保證數(shù)據(jù)的同步,仍然需要我們來處理。

創(chuàng)新互聯(lián)www.cdcxhl.cn,專業(yè)提供香港、美國云服務(wù)器,動(dòng)態(tài)BGP最優(yōu)骨干路由自動(dòng)選擇,持續(xù)穩(wěn)定高效的網(wǎng)絡(luò)助力業(yè)務(wù)部署。公司持有工信部辦法的idc、isp許可證, 機(jī)房獨(dú)有T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確進(jìn)行流量調(diào)度,確保服務(wù)器高可用性。佳節(jié)活動(dòng)現(xiàn)已開啟,新人活動(dòng)云服務(wù)器買多久送多久。

標(biāo)題名稱:Java多線程理解:線程安全的集合對(duì)象-創(chuàng)新互聯(lián)
網(wǎng)站地址:http://www.rwnh.cn/article32/djpcpc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供全網(wǎng)營銷推廣、ChatGPT、響應(yīng)式網(wǎng)站、定制開發(fā)、品牌網(wǎng)站建設(shè)App開發(fā)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

網(wǎng)站托管運(yùn)營
平和县| 高台县| 北安市| 广宗县| 宁陵县| 辰溪县| 安泽县| 离岛区| 牡丹江市| 涿鹿县| 商都县| 平度市| 始兴县| 财经| 景洪市| 榆社县| 曲麻莱县| 英德市| 澎湖县| 定襄县| 梅州市| 琼中| 手机| 马关县| 钦州市| 青铜峡市| 始兴县| 景德镇市| 清涧县| 伊川县| 高邮市| 平乡县| 上林县| 彭水| 汉川市| 广安市| 策勒县| 固阳县| 信丰县| 手游| 肥东县|