真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

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、代碼測(cè)試

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

public?class?Test?{??public?static?void?main(String?[]?args){??????//?用來測(cè)試的List??
??????List?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?data;????public?SampleTask(List?data,CountDownLatch?countDownLatch){????????this.data?=?data;????????this.countDownLatch?=?countDownLatch;
????}????@Override
????public?void?run()?{????????//?每個(gè)線程向List中添加100個(gè)元素??
????????for(int?i?=?0;?i?

7次測(cè)試輸出():

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

public?class?Test?{??public?static?void?main(String?[]?args){??????//?用來測(cè)試的List??
??????List?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?data;????public?SampleTask(List?data,CountDownLatch?countDownLatch){????????this.data?=?data;????????this.countDownLatch?=?countDownLatch;
????}????@Override
????public?void?run()?{????????//?每個(gè)線程向List中添加100個(gè)元素??
????????for(int?i?=?0;?i?

7次測(cè)試輸出():

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

public?class?Test?{??public?static?void?main(String?[]?args){??????//?用來測(cè)試的List??
??????List?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?data;????public?SampleTask(List?data,CountDownLatch?countDownLatch){????????this.data?=?data;????????this.countDownLatch?=?countDownLatch;
????}????@Override
????public?void?run()?{????????//?每個(gè)線程向List中添加100個(gè)元素??
????????for(int?i?=?0;?i?

7次測(cè)試輸出():

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?>?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、線程安全的集合并不安全

分析以下場(chǎng)景:

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è)方法的場(chǎng)景下,我們?nèi)匀恍枰褂胹ynchronized加鎖才能保證對(duì)象的同步。

代碼測(cè)試:

public?class?Test?{??public?static?void?main(String?[]?args){??????//?用來測(cè)試的List??
??????List?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?data;????public?SampleTask(List?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)
當(dāng)前路徑:http://weahome.cn/article/djpcpc.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部