Java并发容器及使用场景
temp10 2025-01-04 23:14:09 java教程 16 ℃ 0 评论
背景
- Java集合容器,主要有四大类别:List Set Queue Map,常见的ArrayList HashMap这些都不是线程安全的
- 同步容器:简单理解为通过synchronized来实现同步的容器,比如Vector、Hashtable以及SynchronizedList等容器
- 同步容器由于共同竞争容器级别的锁,虽然解决了线程安全问题,但是整体吞吐量降低
并发容器设计思路
- 针对多线程并发设计,使用了锁分段技术,只对操作的位置进行同步操作,减小锁的粒度,从而提高吞吐量
- 采用CAS算法和部分代码使用synchronized锁保证线程安全
并发容器分类
List
- CopyOnWriteArrayList目标:代替Vector、synchronizedList原理:利用高并发往往是读多写少的特性,对读操作不加锁,对写操作,先复制一份新的集合,在新的集合上面修改,然后将新集合赋值给旧的引用,并通过volatile 保证其可见性,当然写操作的锁是必不可少的了。
Map
- ConcurrentHashMap目标:代替Hashtable、synchronizedMap,支持复合操作原理:JDK6中采用一种更加细粒度的加锁机制Segment“分段锁”,JDK8中采用CAS无锁算法。
- ConcurrentSkipListMap目标:代替synchronizedSortedMap(TreeMap)原理:Skip list(跳表)是一种可以代替平衡树的数据结构,默认是按照Key值升序的。
Set
- ConcurrentSkipListSet目标:代替synchronizedSortedSet原理:内部基于ConcurrentSkipListMap实现
- CopyOnWriteArraySet目标:代替synchronizedSet原理:基于CopyOnWriteArrayList实现,其唯一的不同是在add时调用的是CopyOnWriteArrayList的addIfAbsent方法,其遍历当前Object数组,如Object数组中已有了当前元素,则直接返回,如果没有则放入Object数组的尾部,并返回。
BlockingQueue
- ArrayBlockingQueue基于数组实现的阻塞FIFO队列通过ReentrantLock实现线程安全,由notEmpty、notFull两个Condition实现阻塞和唤醒
- LinkedBlockingQueue基于链表实现的阻塞FIFO队列通过ReentrantLock实现线程安全,通过Condition实现阻塞和唤醒,由takeLock、putLock两把锁保证并发安全
- SynchronousQueue同步队列,可用于线程间交换数据却不用存储数据队列支持公平和非公平的模式,公平模式的数据结构是队列(FIFO),非公平模式使用的是栈(LIFO)
- LinkedTransferQueue基于链表实现的无界阻塞队列相当于LinkedBlockingQueue和SynchronousQueue的合体,性能比LinkedBlockingQueue更高,比SynchronousQueue能存储更多的元素当put时,如果有等待的线程,就直接将元素 “交给” 等待者, 否则直接进入队列put和transfer方法的区别是,put是立即返回的,transfer是阻塞等待消费者拿到数据才返回。
- PriorityBlockingQueue基于数组实现的支持优先级的无界阻塞队列,底层是基于二叉小顶堆实现通过ReentrantLock实现线程安全,通过Condition实现阻塞和唤醒
- DelayQueue支持延时获取元素的无界阻塞队列,内部使用PriorityQueue来实现进入队列的元素必须实现Delayed接口,在创建元素时可以指定多久才能从队列中获取当前元素,只有在延迟期满时才能从中提取元素
BlockingDeque
- LinkedBlockingDeque基于双向链表实现的阻塞FIFO或FILO队列通过ReentrantLock实现线程安全,通过Condition实现阻塞和唤醒
ConcurrentLinkedQueue
- 并发中的非阻塞队列,采用CAS非阻塞算法实现线程安全
- 基于链表实现的FIFO队列(LinkedList的并发版本)
- 由于使用CAS没有使用锁,所以获取size的时候有可能进行offer,poll或者remove操作,导致获取的元素个数不精确,所以在并发情况下size函数不是很有用。
ConcurrentLinkedDeque
- 并发中的非阻塞队列,采用CAS非阻塞算法实现线程安全
- 基于双向链表实现的FIFO或FILO队列
- 由于使用CAS没有使用锁,所以获取size的时候有可能进行offer,poll或者remove操作,导致获取的元素个数不精确,所以在并发情况下size函数不是很有用。
本文暂时没有评论,来添加一个吧(●'◡'●)