在JDK1.5之前沒有推出同步集合的時候,可以通過Conllections集合工具類的synchronized+集合名稱如:synchronizedSet(Set),現在不需要這種方式了使用
ConcurrentHashMap,
ConcurrentSkipListMap,
ConcurrentSkipListSet,ConcurrentLinkedQueue等這些集合即可.
1>線程不安全的集合出現的問題,死迴圈.Race Condition(也叫做資源競爭),是多線程編程中比較頭疼的問題特別是Java多線程當中,經常會因為多線程同時訪問相同的共用資料,而造成資料的不一致性,為瞭解決這個問題通常來說需要加上同步標識synchronized,來保證資料串列的訪問,但是synchronized是個效能殺手,過多的使用會導致效能下降,特別是擴充性下降,使得系統不能使用多個CPU資源,這是效能測試當中經常遇到的問題. 然而有一個公司的ERP系統出現了問題,然後就叫Java的進階工程師來解決,該工程師通發現當500個並發用訪問的時候,居然把所有的CPU都壓得滿滿的,通過過DTrace for Java工具發現很多CPU都在做同一件事,那就是不停的執行一條語句(HashMap.get()方法).這是為什麼呢?我們知道遍曆Map集合的時候,是這樣的情形(下面只是虛擬碼):while(hasNext()){ //每當迴圈一次cursor加1 //假設該集合裡面有4個元素(count=4),如果迴圈到最後一次了cursor=4,就在此時另一個線程//跑來把集合裡面的一個元素給刪除了(remove()),這時候count=3了,這時候上一個線程接著執行//它會去判斷hasNext(),但是count!=cursor了,而本來是相等的.這樣就是死迴圈了. }hasNext(){ if(cursor==count){ return false;//不需要再迴圈了 } return true;}
總結: 線程不安全的集合,如果多個線程同時對其進行添加和刪除操作, 有可能會出現致命的錯誤.
2>HashSet和HashMap關係通過查看HashSet源碼:
public HashSet() {map =
new HashMap<E,Object>();
} 發現HashSet實際上就是通過HashMap來實現的,不過它只用到了HashMap的key 3>線程不安全集合還有另一個隱患public static void main(String[] args) {
//Collection users = new CopyOnWriteArrayList(); Collection users = new ArrayList(); users.add(new User("張三",28)); users.add(new User("李四",25)); users.add(new User("王五",31)); Iterator itrUsers = users.iterator(); while(itrUsers.hasNext()){ System.out.println("aaaa"); User user = (User)itrUsers.next(); if("張三".equals(user.getName())){ users.remove(user); } else { System.out.println(user); } }
}
運行程式發現出現異常:
這是為什麼?跟進AbstractList 343行:
分析如下:我們來看一下這個
while(itrUsers.hasNext()){ User user = (User)itrUsers.next(); if("張三".equals(user.getName())){ users.remove(user); } else { System.out.println(user); }}查看hasNext源碼:
如果把 if("張三".equals(user.getName()))改成 if("王五".equals(user.getName()))輸出結果如下:
出現了第一次出現的異常,分析如下:當第一迴圈執行到next()時候expectedModCount=3 modCount=3 cursor=1,size()=3當第二迴圈執行到next()時候expectedModCount=3 modCount=3 cursor=2,size()=3當第三迴圈執行到next()時候expectedModCount=3 modCount=4 cursor=3,size()=2發現cursor任然不等於size(),迴圈人仍在繼續,最後發現expectedModCount!=modCount拋出異常.所以控制太輸出這樣的結果. 要想迭代的時候同時操作集合可以使用JDK1.5提供的安全執行緒的集合,只需要把集合改成如下即可:Collection users = new CopyOnWriteArrayList();
轉載請註明出處 : http://blog.csdn.net/johnny901114/article/details/8696032