標籤:集合 java
使用情境
1.多線程
(1)在jdk1.5之前原始的集合類中,只有vector、stack、hashtable、enumeration等是安全執行緒的,其他的都是非安全執行緒的。
非安全執行緒的集合在多線程操作中,會出現髒資料,如
final List<String> tickets = new ArrayList<String>(); for (int i = 0; i < 100000; i++) { tickets.add("NO," + i); } System.out.println("start1..."); for (int i = 0; i < 5; i++) { Thread thread = new Thread() { public void run() { while (true) { if (tickets.size() > 0) System.out.println("thread:"+Thread.currentThread().getId()+" "+ tickets.remove(0)); else break; } } }; thread.start(); }
運行結果:
......thread:13 NO,98687thread:12 NO,96534thread:10 NO,96534thread:10 NO,98687......thread:10 nullthread:12 null
線程不安全導致多個線程調用 remove 時同時操作 List 進行讀寫。
ArrayList修改成 Stack,問題解決。
(2)安全執行緒的集合也需要遵守fail-fast的檢測機制,即在迭代的時候,不能修改集合的元素。一旦發現違反這個規定就會拋出ConcurrentModificationException異常。如需在迭代過程中修改元素,需要對迭代和修改加同步鎖。
如下面代碼將出現ConcurrentModificationException異常。
final List<String> tickets = Collections .synchronizedList(new ArrayList<String>()); for (int i = 0; i < 100; i++) { tickets.add("NO," + i); } System.out.println("start1..."); for (int i = 0; i < 5; i++) { Thread thread = new Thread() { public void run() { while (true) { if (tickets.size() > 0) System.out.println("thread:" + Thread.currentThread().getId() + " " + tickets.remove(0)); else break; } } }; thread.start(); } System.out.println("start2..."); new Thread() { public void run() { for (String s : tickets) { System.out.println(s); } } }.start();
(3)擷取安全執行緒的集合
1.使用vector、stack、hashtable、enumeration等安全執行緒的集合類。
2.使用Collections.synchronizedxxx 將非安全執行緒的集合轉換成安全執行緒的集合。
3.使用 jdk1.5之後新的安全執行緒集合類,如ConcurrentLinkedQueue、ConcurrentHashMap等。
2.使用注意事項
(1)ArrayList 等順序存放集合適合隨機訪問,LinkList 等鏈表形式存放集合適合插入刪除和迭代操作。
(2)Collection介面繼承了Iterable介面,除 map 外每個集合都支援迭代遍曆和 foreach 功能。
(3)WeakHashMap支援 key 回收,提升效能,在開源項目Android-Universal-Image-Loader 中用WeakHashMap儲存需要顯示的 ImageView 支援回收。
(4)HashMap 的 key 判斷相同的標準是 key 的 equal 和 hashcode 相同。如下
private static void testHashMapKey() { System.out.println("------test hash map key start------"); String[] sampleTest = { "Aa", "BB", "aa" }; HashMap<StringEqual, Integer> strHaspMap = new HashMap<HashMapDemo.StringEqual, Integer>(); StringEqual[] strArray = { new StringEqual(sampleTest[0]), new StringEqual(sampleTest[1]), new StringEqual(sampleTest[2]) }; //key是否相同的判斷是equal和hash都相同,Aa和BB的hash相同 strHaspMap.put(strArray[0], 0); strHaspMap.put(strArray[1], 1); strHaspMap.put(strArray[2], 2); Set<StringEqual> set = strHaspMap.keySet(); for (StringEqual str : set) { System.out.println(strHaspMap.get(str)); } } private static class StringEqual { private String str; public StringEqual(String str) { this.str = str; } @Override public boolean equals(Object obj) { return true; } @Override public int hashCode() { return str.hashCode(); } }
------test hash map key start------12
String 的 hashcode 演算法是s[0]*31^(n-1) + s[1]*31^(n-2) + … + s[n-1],”Aa”和”BB”的hash相同,StringEqual類的 equal 預設為 true,則”Aa”和”BB”認定為同一個 key。
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
java-集合類(二)