java5同步集合类的应用

一、包装线程不安全的集合

ArrayListLinkedListHashSetTreeSetHashMapTreeMap等都是线程不安全的。当多个并发线程向这些集合中存、取元素时,就可能破坏这些集合的数据完整性。

如果程序中有多个线程可能访问以上这些集合,就可以使用Collections提供的类方法把这些集合包装成线程安全的集合。

返回值 方法名 描述
static <T> Collection<T> synchronizedCollection(Collection<T> c) 返回指定 collection 支持的同步(线程安全的)collection。
static<T> List<T> synchronizedList(List<T> list) 返回指定列表支持的同步(线程安全的)列表。
static<K,V> Map<K,V> synchronizedMap(Map<K,V> m) 返回由指定映射支持的同步(线程安全的)映射
static<T> Set<T> synchronizedSet(Set<T> s) 返回指定 set 支持的同步(线程安全的)set
static<K,V> SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V> m) 返回指定有序映射支持的同步(线程安全的)有序映射。

如果像将传统的集合变成安全的,可以到Collections中找对应的静态方法。

主要使用代理的方式实现安全(具体可以查看源码),通过一个内部类。

private static class SynchronizedMap<K,V>
        implements Map<K,V>, Serializable {
        private static final long serialVersionUID = 1978198479659022715L;

        private final Map<K,V> m;     // Backing Map
        final Object      mutex;        // Object on which to synchronize
        //所有的方法都需要使用到mutex。 所以在多线程的情况下,使用
        //这种方式去进行同步效率还是比较低的。

        SynchronizedMap(Map<K,V> m) {
            this.m = Objects.requireNonNull(m);
            mutex = this;
        }

        SynchronizedMap(Map<K,V> m, Object mutex) {
            this.m = m;
            this.mutex = mutex;
        }

        public int size() {
            synchronized (mutex) {return m.size();}
        }
        ……
 }

但是,这些集合通常效率不是很高。


二、线程安全的集合类

从java5 开始,在java.util.concurrent包下,提供了大量支持高效并发访问的集合接口和实现类

这些线程安全的集合类可大致分为两类。以Concurrent开头的集合类,和 以CopyOnWrite开头的集合类。
Concurrent开头的集合类采用了更加复杂的算法来保证永远不会锁住整个集合,因此在并发写入时有较好的性能

在默认情况下,ConcurrentHashMap支持16个线程并发写入,当超过16个线程并发向该Map写入时,可能有一些线程需要等待,实际上,可通过concurrencyLevel构造参数来支持更多并发写入线程。

与HashMap等普通集合不同,ConcurrentLinkedQueueConcurrentHashMap支持多线程并发访问,所以当使用迭代器来遍历集合元素时,该迭代器可能不能反映出创建迭代器之后所做的修改,但程序不会抛出任何异常。


CopyOnWriteArrayList集合。它采用了复制底层数组的方式来实现写操作。由于执行写入操作时需要频繁地复制数组,性能比较差。因此CopyOnWriteArrayList适合在读取操作远大于写入操作的场景,例如缓存等。


部分工具类描述

描述
ConcurrentHashMap 一个高效的并发HashMap
CopyOnWriteArrayList 在读多写少的场合,这个List性能非常好,远远好于Vector
ConcurrentLinkedQueue 高效的并发队列,使用链表实现。 可以看做一个线程安全的LinkedList
BlockiingQueue 是一个接口,非常适合用于做数据共享的通道
ConcurrentSkipListMap 跳表的实现。是一个Map,使用跳表的数据结构进行快速查找

三、案例

这里写图片描述


每个段都有独立的锁。实现了并行,提高了效率; 在1.8以后又采用 了CAS算法去实现同步


3.1 java.util.Collections包中的并发类

使用Collections包中的并发类,去实现同步,但是多线程并发执行修改数据,抛出异常:并发修改异常

package test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;


public class TestCopyOnWriteArrayList {

    public static void main(String[] args) {
        HelloThread ht = new HelloThread();

        for (int i = 0; i < 10; i++) {
            new Thread(ht).start();
        }
    }

}

class HelloThread implements Runnable{

    private static List<String> list = Collections.synchronizedList(new ArrayList<String>());


    static{
        list.add("AA");
        list.add("BB");
        list.add("CC");
    }

    @Override
    public void run() {

        Iterator<String> it = list.iterator();

        while(it.hasNext()){
            System.out.println(it.next());

            list.add("AA");
        }

    }

}

运行结果

这里写图片描述


3.2 java.util.concurrent包中的并发类

CopyOnWriteArrayList/CopyOnWriteArraySet : 写入并复制

注意: 添加操作多时,效率低,因为每次添加时都会进行复制,开销非常的大。并发迭代操作多时可以选择

package test;


import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArrayList;


public class TestCopyOnWriteArrayList {

    public static void main(String[] args) {
        HelloThread ht = new HelloThread();

        for (int i = 0; i < 10; i++) {
            new Thread(ht).start();
        }
    }

}

class HelloThread implements Runnable{

    private static CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();


    static{
        list.add("AA");
        list.add("BB");
        list.add("CC");
    }

    @Override
    public void run() {

        Iterator<String> it = list.iterator();

        while(it.hasNext()){
            System.out.println(it.next());

            list.add("AA");
        }

    }

}

运行结果正常。


参考

软件包 java.util.concurrent 的描述 http://tool.oschina.net/apidocs/apidoc?api=jdk-zh

猜你喜欢

转载自blog.csdn.net/qq_31156277/article/details/80517483
今日推荐