java 多线程集合操作_多线程中使用Java集合类
Java集合類中,某個線程在 Collection 上進(jìn)行迭代時,通常不允許另一個線性修改該 Collection。通常在這些情況下,迭代的結(jié)果是不確定的。如果檢測到這種行為,一些迭代器實現(xiàn)(包括 JRE 提供的所有通用 collection 實現(xiàn))可能選擇拋出此異常。執(zhí)行該操作的迭代器稱為快速失敗 迭代器,因為迭代器很快就完全失敗,而不會冒著在將來某個時間任意發(fā)生不確定行為的風(fēng)險。
因此,當(dāng)一個線程試圖ArrayList的數(shù)據(jù)的時候,另一個線程對ArrayList在進(jìn)行迭代的,會出錯,拋出ConcurrentModificationException。
比如下面的代碼:
finalList?tickets?=newArrayList();
for(inti?=0;?i?<100000;?i++)?{
tickets.add("ticket?NO,"+?i);
}
System.out.println("start1...");
for(inti?=0;?i?<10;?i++)?{
Thread?salethread?=?newThread()?{
public?voidrun()?{
while(tickets.size()?>0)?{
tickets.remove(0);
System.out.println(Thread.currentThread().getId()+"Remove?0");
}
}
};
salethread.start();
}
System.out.println("start2...");
newThread()?{
public?voidrun()?{
for(String?s?:?tickets)?{
System.out.println(s);
}
}
}.start();
上述程序運行后,會在某處拋出異常:
java.util.ConcurrentModificationException at java.util.ArrayList$Itr.checkForComodification(Unknown Source) at java.util.ArrayList$Itr.next(Unknown Source) at mytest.mytestpkg.Tj$2.run(Tj.java:138)
Vector是線程同步的,那么把ArrayList改成Vector是不是就對了呢?
答案是否定的,事實上,無論是ArrayList還是Vector,只要是實現(xiàn)Collection接口的,都要遵循fail-fast的檢測機制,即在迭代是時候,不能修改集合的元素。一旦發(fā)現(xiàn)違法這個規(guī)定就會拋出異常。
--------------------------------------------------------------------------------
事實上,Vector相對于ArrayList的線程同步,體現(xiàn)在對集合元素是否臟讀上。即ArrayList允許臟讀,而Vector特殊的機制,不會出現(xiàn)臟讀,但是效率會很差。
舉個例子,一個集合,有10個線程從該集合中刪除元素,那么每個元素只可能由一個線程刪除掉,不可能會出現(xiàn)一個元素被多個線程刪除的情況。
比如下面的代碼:
finalList?tickets?=newArrayList();
for(inti?=0;?i?<100000;?i++)?{
tickets.add("ticket?NO,"+?i);
}
System.out.println("start1...");
for(inti?=0;?i?<10;?i++)?{
Thread?salethread?=?newThread()?{
public?voidrun()?{
while(true)?{
if(tickets.size()>0)
System.out.println(Thread.currentThread().getId()+?tickets.remove(0));
else
break;
}
}
};
salethread.start();
}
for循環(huán)構(gòu)造10個線程刪除同一個集合中的數(shù)據(jù),理論上只能刪除100000次。但是運行完發(fā)現(xiàn),輸出的刪除次數(shù)108494次,其中很多數(shù)據(jù)都是被多個線程刪除,比如下面的輸出片段:
17ticket NO,35721 14ticket NO,35699 11ticket NO,35721 18ticket NO,35721 17ticket NO,35729 11ticket NO,35729 14ticket NO,35729 17ticket NO,35729 14ticket NO,35734 17ticket NO,35734 13ticket NO,35721
可以看到35721,35729都被多個線程刪除。這事實上就是出現(xiàn)了臟讀。解決的辦法就是加鎖,使得同一時刻只有1個線程對ArrayList做操作。
修改代碼,synchronized關(guān)鍵字,讓得到鎖對象的線程才能運行,這樣確保同一時刻只有一個線程操作集合。
finalList?tickets?=newArrayList();
for(inti?=0;?i?<100000;?i++)?{
tickets.add("ticket?NO,"+?i);
}
System.out.println("start1...");
finalObject?lock=newObject();
for(inti?=0;?i?<10;?i++)?{
Thread?salethread?=?newThread()?{
public?voidrun()?{
while(true)?{
synchronized(lock)
{
if(tickets.size()>0)
System.out.println(Thread.currentThread().getId()+?tickets.remove(0));
else
break;
}
}
}
};
salethread.start();
}
這樣得到的結(jié)果就是準(zhǔn)確的了。
當(dāng)然,不使用synchronized關(guān)鍵字,而直接使用vector或者Collections.synchronizedList 也是同樣效果:
finalList?tickets?=java.util.Collections.synchronizedList(newArrayList());
finalList?tickets?=newVector();
vector和Collections.synchronizedList 都是線程同步的,避免的臟讀的出現(xiàn)。
posted on 2013-02-28 11:33 順其自然EVO 閱讀(175) 評論(0) ?編輯 ?收藏
總結(jié)
以上是生活随笔為你收集整理的java 多线程集合操作_多线程中使用Java集合类的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java排队买票_【排队买票】 (Jav
- 下一篇: java swt webkit_使用Ja