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,98687
thread:12 NO,96534
thread:10 NO,96534
thread:10 NO,98687
......
thread:10 null
thread: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------
1
2

String 的 hashcode 算法是s[0]*31^(n-1) + s[1]*31^(n-2) + … + s[n-1],”Aa”和”BB”的hash相同,StringEqual類的 equal 默認爲 true,則”Aa”和”BB”認定爲同一個 key。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章