什么是JUC高并发容器?

举报
别团等shy哥发育 发表于 2023/10/06 16:46:12 2023/10/06
【摘要】 线程安全的同步容器类Java同步容器类通过Synchronized(内置锁)来实现同步的容器,比如Vector、HashTable以及SynchronizedList等容器。线程安全的同步容器类主要有Vector、Stack、HashTable等。另外,Java还提供了一组包装方法,将一个普通的基础容器包装成一个线程安全的同步容器。例如通过Collections.synchronized包...

线程安全的同步容器类

Java同步容器类通过Synchronized(内置锁)来实现同步的容器,比如Vector、HashTable以及SynchronizedList等容器。线程安全的同步容器类主要有VectorStackHashTable等。另外,Java还提供了一组包装方法,将一个普通的基础容器包装成一个线程安全的同步容器。

例如通过Collections.synchronized包装方法能将一个普通的SortedSet容器包装成一个线程安全额SortedSet

1.通过synchronizedSortedSet静态方法包装出一个同步容器

public class CollectionsDemo {
    public static void main(String[] args) throws InterruptedException {
        //创建一个基础的有序集合
        SortedSet<String> elementSet=new TreeSet<>();
        //增加元素
        elementSet.add("element 1");
        elementSet.add("element 2");

        //将element包装成一个同步容器
        SortedSet<String> sortedSet = Collections.synchronizedSortedSet(elementSet);
        //输出容器中的元素
        System.out.println("SortedSet is :"+sortedSet);
        CountDownLatch latch = new CountDownLatch(5);
        ExecutorService pool = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 5; i++) {
            int finalI=i;
            pool.submit(()->{
                //向同步容器中增加一个元素
                sortedSet.add("element "+(3+finalI));
                System.out.println("add element"+(3+finalI));
                latch.countDown();
            });
        }
        latch.await();
        //输出容器中的元素
        System.out.println("SortedSet is :"+sortedSet);
    }
}

image-20230917175555706

2.java.util.Collections所提供的同步包装方法

java.util.Collections还提供了一系列对其他的基础容器进行同步包装的方法,如synchronizedList()方法将基础List包装成线程安全的列表容器,synchronizedMap()方法将基础Map容器包装成线程安全的容器,synchronizedCollection()方法将基础Collection容器包装成线程安全的Collection容器。

同步包装方法如下:

image-20230917182029322

与同步包装方法相对应,java.util.Collections还提供了一系列同步包装类,这些包装类都是其内部类。这些同步包装类的实现逻辑很简单:实现了容器的操作接口,在操作接口上使用synchronized进行线程同步,然后在synchronized的临界区将实际的操作委托给被包装的基础容器。

3.同步容器面临的问题

可以通过查看Vector、HashTable、java.util.Collections同步包装类的源码,发现这些同步容器实现线程安全的方式是:在需要同步访问的方法上添加synchronized关键字。

synchronized在线程没有发生争用的场景下处于偏向锁的状态,其性能非常高。但是,一旦发生了线程争用,synchronized会由偏向锁膨胀成重量级锁,在抢占和释放时发生CPU内核态与用户态切换,所以削弱了并发性,降低了吞吐量,而且会严重影响性能。

因此,为了解决同步容器的性能问题,有了JUC高并发容器。

什么是高并发容器?

JUC高并发容器是基于非阻塞算法(或者无锁编程算法)实现的容器类,无锁编程算法主要通过CAS(Compare And Swap)+volatile组合实现,通过CAS保障操作的原子性,通过volatile保障变量内存的可见性。无锁编程算法的主要优点如下:

  • 开销较小:不需要在内核态和用户态之间切换进程。
  • 读写不互斥:只有写操作需要使用基于CAS机制的乐观锁,读读操作之间可以不用互斥。

1.List

JUC包中的高并发List主要有CopyOnWriteArrayList,对应的基础容器为ArrayList

CopyOnWriteArrayList相当于线程安全的ArrayList,它实现了List接口。在读多写少的场景中,其性能远远高于ArrayList的同步包装容器。

2.Set

JUC包中的Set主要有CopyOnWriteArraySetConcurrentSkipListSet

  • CopyOnWriteArraySet继承自AbstractSet类,对应的基础容器为HashSet。其内部组合了一个CopyOnWriteArrayList对象,它的核心操作是基于CopyOnWriteArrayList实现的。
  • ConcurrentSkipListSet是线程安全的有序集合,对应的基础容器为TreeSet。它继承自AbstractSet,并实现了NavigableSet接口。ConcurrentSkipListSet是通过ConcurrentSkipListMap实现的。

3.Map

JUC包中Map主要有ConcurrentHashMapConcurrentSkipListMap

  • ConcurrentHashMap对应的基础容器为HashMap。JDK6中的ConcurrentHashMap采用一种更加细粒度的分段锁加锁机制,JDK8基于Synchronized+CAS实现。
  • ConcurrentSkipListMap对应的基础容器为TreeMap。其内部的Skip List(跳表)结构是一种可以代替平衡树的数据结构,默认是按照Key值升序的。

4.Queue

JUC包中的Queue的实现类包括三类:单向队列、双向队列和阻塞队列。

  • ConcurrentLinkedQueue是基于列表实现的单向队列,按照FIFO(先入先出)原则对元素进行排序。新元素从队列尾部插入,而获取队列元素则需要从队列头部获取。
  • ConcurrentLinkedDeque是基于链表的双向队列,但是该队列不允许null元素。作为双向队列,ConcurrentLinkedDeque可以当作“栈”来使用,并且高效地支持并发环境。

JUC还扩展了队列,增加了可阻塞地插入和获取等操作,提供了一组阻塞队列,具体如下:

  • ArrayBlockingQueue:基于数组实现的可阻塞地FIFO队列。
  • LinkedBlockingQueue:基于链表实现的可阻塞的FIFO队列。
  • PriorityBlockingQueue:按优先级排序的队列。
  • DelayQueue:按照元素的Delay时间进行排序的队列。
  • SynchronousQueue:无缓冲等待队列。
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。