天天看点

并发类容器(一)

并发类容器(一)

        Java5.0提供了多种并发容器类来改进同步类容器的性能。同步容器将所有对容器状态的访问都串行化,以实现它们的线程安全性。这种方法的代价是严重降低并发性,当多个线程竞争容器的锁时,吞吐量将严重降低。

        并发容器是针对多个线程并发访问设计的。在Java5.0中增加了ConcurrentHashMap,用来替代同步基于散列的Map,以及CopyOnWriteArrayList,用于在遍历操作为主要操作(读多写少)的情况下代替同步的List。在新的ConcurrentMap接口中增加了对一些常见复合操作的支持,例如“若没有则添加”、替换以及有条件删除等。Java6引入了ConcurrentSkipListMap和ConcurrentSkipListSet,分别作为同步的SortedMap和SortedSet的并发替代品(例如用synchronizedXxx包装的TreeMap、TreeSet)。Java5.0还增加了两种新的容器类型Queue和BlockingQueue。Queue的主要实现是ConcurrentLinkedQueue,传统的先进先出队列。Queue不会阻塞,如果队列为空,那么获取元素就会返回空值。BlockingQueue扩展了Queue,增加了可阻塞的插入和获取操作。

        通过并发类容器来代替同步容器,可以极大地提高伸缩性并降低风险。

一、ConcurrentHashMap

        ConcurrentHashMap也是一个基于散列的Map,但它使用了一种完全不同的加锁策略来提供更好并发性和伸缩性。ConcurrentHashMap并不是将每个方法都在同一个锁上同步并使的每次只能有一个线程访问容器,而是使用了一种粒度更细的加锁机制来实现更大层度的共享,这种机制为分段锁。在这种机制中,任意数量的读线程可以并发的访问Map,执行读取操作的线程和执行写入操作的线程可以并发地访问Map,并且一定数量的写入线程可以并发地修改Map。ConcurrentHashMap带来的结果是,在并发访问环境下将实现更高的吞吐量,而在单线程环境中只损失非常小的性能。

        ConcurrentHashMap内部是分段的(Segment),最多可以有16个Segment,每一个Segment内部就像是一个HashTable,也就是说,理论上在这时最多可以支持16的线程并发的写,只要它们分到不同的Segment上。

        ConcurrentHashMap的使用:

public class UseConcurrentHashMap {

    public static void main(String[] args) {
        ConcurrentHashMap<String,String> map = new ConcurrentHashMap<>();
        map.put("zs","23");
        map.put("ls","24");
        map.putIfAbsent("ww","25");
        //如果没有则添加
        map.putIfAbsent("ww","111");

        map.entrySet().forEach(entry -> {
            System.out.println("key : " + entry.getKey() + " , value : " + entry.getValue());
        });

        System.out.println("=================remove===================");
        //映射到指定值才删除
        map.remove("zs","111");

        map.entrySet().forEach(entry -> {
            System.out.println("key : " + entry.getKey() + " , value : " + entry.getValue());
        });

        //映射到指定值才替换
        map.replace("ls","26","26");
        System.out.println("=================replace===================");
        map.entrySet().forEach(entry -> {
            System.out.println("key : " + entry.getKey() + " , value : " + entry.getValue());
        });
    }
}      

二、CopyOnWriteArrayList

        CopyOnWriteArrayList用于替代List,在读多写少的情况下提供了更好的性能。

public class UseCopyOnWriteArrayList {

    public static void main(String[] args) {

        CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
        list.add("a");
        //添加元素,如果不存在
        list.addIfAbsent("b");
        list.addIfAbsent("b");
        list.add("c");

        list.forEach(System.out ::println);

    }
}