java 并发容器

java并发容器基本可以分为4个,list,map,set,queue,如下如:

1

1 list 

只有一个实现 CopyOnWriteArrayList ,顾名思义就是写的时候会将共享变量新复制一份出来,这样做的好处是读操作完全无锁。

但是新插入的数据不会立即更新,对源数据的增,删,改是没用的。

适用于读多写少

2 Map

Map 接口的两个实现是 ConcurrentHashMap 和 ConcurrentSkipListMap,它们从应用的角度来看,主要区别在于ConcurrentHashMap 的 key 是无序的,而 ConcurrentSkipListMap 的 key 是有序的。所以如果你需要保证 key 的顺序,就只能使用 ConcurrentSkipListMap。

使用 ConcurrentHashMap 和 ConcurrentSkipListMap 需要注意的地方是,它们的 key 和 value 都不能为空,否则会抛出NullPointerException这个运行时异常。下面这个表格总结了 Map 相关的实现类对于 key 和 value 的要求,你可以对比学习。

都是使用的分段锁策略。具体策略为:每个map都有一个segment,类似于map结构,当存数据的时候,先通过hash算法找到对应的segment,在通过hash算法找到segment中下标,存入对应数据,只需要锁一个segment就好,不需要锁住全表。

3 set

 CopyOnWriteArraySet 和 ConcurrentSkipListSet

4 队列

从俩个维度分析,一个维度是阻塞与非阻塞,所谓阻塞指的是当队列已满时,入队操作阻塞;当队列已空时,出队操作阻塞。另一个维度是单端与双端,单端指的是只能队尾入队,队首出队;而双端指的是队首队尾皆可入队出队。Java 并发包里阻塞队列都用 Blocking 关键字标识,单端队列使用 Queue 标识,双端队列使用 Deque 标识

使用put和take操作,其他操作不能保证线程安全

 

1 单端阻塞队列:

ArrayBlockingQueue、LinkedBlockingQueue、SynchronousQueue、LinkedTransferQueue、PriorityBlockingQueue 和 DelayQueue。内部一般会持有一个队列,这个队列可以是数组(其实现是 ArrayBlockingQueue)也可以是链表(其实现是 LinkedBlockingQueue);甚至还可以不持有队列(其实现是 SynchronousQueue),此时生产者线程的入队操作必须等待消费者线程的出队操作。

 LinkedTransferQueue 融合 LinkedBlockingQueue 和 SynchronousQueue 的功能,性能比 LinkedBlockingQueue 更好

PriorityBlockingQueue 支持按照优先级出队;无界,通过堆数据结果来实现。 

DelayQueue 支持延时出队。无界,通过堆数据结构来实现

SynchronousQueue :是一个不存储元素的队列,每一个put操作必须等改一个take操作,否则不能进行添加

SynchronousQueue<Integer> queue = new SynchronousQueue(true);

        new Thread(()-> {
            try {
                System.out.println(queue.take());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
        queue.put(1);

2 双端阻塞队列

LinkedBlockingDeque: 可以用作工作窃取。 

工作窃取(work-stealing)算法是指某个线程从其他队列里窃取任务来执行。
一个大任务分割为若干个互不依赖的子任务,为了减少线程间的竞争,把这些子任务分别放到不同的队列里,并未每个队列创建一个单独的线程来执行队列里的任务,线程和队列一一对应。比如线程1负责处理1队列里的任务,2线程负责2队列的。但是有的线程会先把自己队列里的任务干完,而其他线程对应的队列里还有任务待处理。干完活的线程与其等着,不如帮其他线程干活,于是它就去其他线程的队列里窃取一个任务来执行。而在这时它们可能会访问同一个队列,所以为了减少窃取任务线程和被窃取任务线程之间的竞争,通常会使用双端队列,被窃取任务线程永远从双端队列的头部拿任务执行,而窃取任务线程永远从双端队列的尾部拿任务执行。

如Java中的fork/join模型就是利用了工作窃取来实现的。 

3 单端非阻塞队列:

其实现是 ConcurrentLinkedQueue。
4 双端非阻塞队列:

其实现是 ConcurrentLinkedDeque。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值