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。

原文地址:https://www.cnblogs.com/jzssuanfa/p/7100377.html