java常见并发容器
并发容器
引言
为了应对高并发过程中,数据一致性的问题,java中设计了一些并发容器。本篇将从容器的类别出发,介绍各个容器的特点及原理,为接下来的线程池做准备。
List相关
Vector
Vector是最古老的并发容器,其实现了List接口,方法都是默认加synchronized的,所以效率很低,现在基本不会用它。
示例
用到的锁 synchronized
public synchronized int lastIndexOf(Object o) {return lastIndexOf(o, elementCount-1);}
CopyOnWriteArrayList
读时没影响不加锁,写时加锁,copy一个新list,然后扩展一个新元素,老引用指向新的。
示例
用到的锁 ReentrantLock
// 写时加锁
public boolean add(E e) {final ReentrantLock lock = this.lock;lock.lock();try {Object[] elements = getArray();int len = elements.length;Object[] newElements = Arrays.copyOf(elements, len + 1);newElements[len] = e;setArray(newElements);return true;} finally {lock.unlock();}}
常见同步方法
Set相关
CopyOnWriteArraySet
底层是数组,读时没影响不加锁,写时加锁,copy一个新list,然后扩展一个新元素,老引用指向新的。
ConcurrentSkipListSet
ConcurrentSkipListSet是线程安全的有序的哈希表,其底层用的是跳表,其特点主要在有序上面。
示例
用到的锁 synchronized
final V putVal(K key, V value, boolean onlyIfAbsent) {if (key == null || value == null) throw new NullPointerException();int hash = spread(key.hashCode());int binCount = 0;for (Node<K,V>[] tab = table;;) {Node<K,V> f; int n, i, fh;if (tab == null || (n = tab.length) == 0)tab = initTable();else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {if (casTabAt(tab, i, null,new Node<K,V>(hash, key, value, null)))break; // no lock when adding to empty bin}else if ((fh = f.hash) == MOVED)tab = helpTransfer(tab, f);else {V oldVal = null;synchronized (f) { // 加锁if (tabAt(tab, i) == f) {if (fh >= 0) {binCount = 1;for (Node<K,V> e = f;; ++binCount) {K ek;if (e.hash == hash &&((ek = e.key) == key ||(ek != null && key.equals(ek)))) {oldVal = e.val;if (!onlyIfAbsent)e.val = value;break;}Node<K,V> pred = e;if ((e = e.next) == null) {pred.next = new Node<K,V>(hash, key,value, null);break;}}}else if (f instanceof TreeBin) {Node<K,V> p;binCount = 2;if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,value)) != null) {oldVal = p.val;if (!onlyIfAbsent)p.val = value;}}}}if (binCount != 0) {if (binCount >= TREEIFY_THRESHOLD)treeifyBin(tab, i);if (oldVal != null)return oldVal;break;}}}addCount(1L, binCount);return null;}
Map相关
HashTable
和Vector一样古老的并发容器,其实现了Map接口,方法都是默认加synchronized的,效率低,基本也不用了。
示例
用到的锁 synchronized
public synchronized boolean isEmpty() {return count == 0;}
HashMap
HashMap的方法默认都是不加锁的,可以通过容器工具类的方法Collections.synchronizedMap(new HashMap<UUID, UUID>(),给它手动加锁,加锁后效率和HashTable差不多。
ConcurrentHashMap
ConcurrentHashMap底层用的分段锁,所以其在效率上会有所提升,主要体现在读上面。由于它往里插的时候内部做了各种各样的判断,本来是链表的,到8之后又变成了红黑树,然后里面又做了各种各样的cas的判断,所以他往里插的数据相比HashTable还要低一点。
ConcurrentSkipListMap
ConcurrentSkipListMap是线程安全的有序的哈希表,其底层用的是跳表。其特点主要在有序上面,效率相较ConcurrentHashMap略低。
Queue相关
LinkedBlockingDeque
双端阻塞队列,实现put阻塞,take阻塞。底层用的是LockSupport.park(),自然而然的实现生产者,消费者模型。
示例
用到的锁 ReentrantLock
public void putLast(E e) throws InterruptedException {if (e == null) throw new NullPointerException();Node<E> node = new Node<E>(e);final ReentrantLock lock = this.lock;lock.lock();try {while (!linkLast(node))notFull.await();} finally {lock.unlock();}}
ArrayBlockingQueue
底层是数组实现的阻塞队列,实现put阻塞,take阻塞。底层用的是LockSupport.park(),自然而然的实现生产者,消费者模型。
示例
用到的锁 ReentrantLock
public boolean offer(E e) {checkNotNull(e);final ReentrantLock lock = this.lock;lock.lock();try {if (count == items.length)return false;else {enqueue(e);return true;}} finally {lock.unlock();}}
PriorityBlockingQueue
底层用的堆结构,除了阻塞队列的特点外,可以根据比较器,每次取值获取最大值或最小值。
LinkedBlockingQueue
底层是单向链表实现的阻塞队列,实现put阻塞,take阻塞。底层用的是LockSupport.park(),自然而然的实现生产者,消费者模型。
SynchronousQueue
SynchronousQueue容量为0,它不是用来装内容的,SynchronousQueue是专门用来两个线程之间传内容的。使用中一个线程take阻塞,等待另一个线程put,或者一个线程put阻塞,等待另一个线程take。
用到的锁 CAS自旋锁
void advanceTail(QNode t, QNode nt) {if (tail == t)UNSAFE.compareAndSwapObject(this, tailOffset, t, nt);}
LinkedTransferQueue
TransferQueue可以给线程来传递任务,以此同时不像是SynchronousQueue只能传递一个,TransferQueue做成列表可以传好多个。它添加了一个方法叫transfer,如果我们用put就相当于一个线程来了往里一装它就走了。transfer就是装完在这等着,阻塞等有人把它取走我这个线程才回去干我自己的事情。
示例
用到的锁 LockSupport
private E xfer(E e, boolean haveData, int how, long nanos) {if (haveData && (e == null))throw new NullPointerException();Node s = null; // the node to append, if neededretry:for (;;) { // restart on append racefor (Node h = head, p = h; p != null;) { // find & match first nodeboolean isData = p.isData;Object item = p.item;if (item != p && (item != null) == isData) { // unmatchedif (isData == haveData) // can't matchbreak;if (p.casItem(item, e)) { // matchfor (Node q = p; q != h;) {Node n = q.next; // update by 2 unless singletonif (head == h && casHead(h, n == null ? q : n)) {h.forgetNext();break;} // advance and retryif ((h = head) == null ||(q = h.next) == null || !q.isMatched())break; // unless slack < 2}LockSupport.unpark(p.waiter);return LinkedTransferQueue.<E>cast(item);}}Node n = p.next;p = (p != n) ? n : (h = head); // Use head if p offlist}if (how != NOW) { // No matches availableif (s == null)s = new Node(e, haveData);Node pred = tryAppend(s, haveData);if (pred == null)continue retry; // lost race vs opposite modeif (how != ASYNC)return awaitMatch(s, pred, e, (how == TIMED), nanos);}return e; // not waiting}}
ConcurrentLinkedQueue
并发非阻塞队列,每次offer和poll时会进行cas操作,保证并发的原子性。
DelayQueue
本质用的是PriorityQueue,只是让加入的对象实现时间上的排序。
示例
用到的锁:ReentrantLock
public boolean offer(E e) {final ReentrantLock lock = this.lock;lock.lock();try {q.offer(e);if (q.peek() == e) {leader = null;available.signal();}return true;} finally {lock.unlock();}}
写在最后
本文简单介绍了几类并发容器,给了几个示例代码,算是抛砖引玉吧。
java常见并发容器相关推荐
- 谈谈java的并发容器、Queue
目录 同步类容器 并发类容器 ConcurrentMap:支持高并发下线程安全. Copy-On-Write容器:最好在读多写少的情况下使用. 并发Queue 同步类容器 同步类容器是线程安全的. / ...
- Java集合之并发容器
一:java中的并发容器总结 JDK提供的这些容器大部分在 java.util.concurrent 包中. ConcurrentHashMap: 线程安全的HashMap CopyOnWriteAr ...
- 探索JAVA并发 - 并发容器全家福!
作者:acupt,专注Java,架构师社区合伙人! 14个并发容器,你用过几个? 不考虑多线程并发的情况下,容器类一般使用ArrayList.HashMap等线程不安全的类,效率更高.在并发场景下,常 ...
- java 头尾 队列_探索JAVA并发 - 并发容器全家福
14个并发容器,你用过几个? 不考虑多线程并发的情况下,容器类一般使用ArrayList.HashMap等线程不安全的类,效率更高.在并发场景下,常会用到ConcurrentHashMap.Array ...
- 和朱晔一起复习Java并发(五):并发容器和同步器
和朱晔一起复习Java并发(五):并发容器和同步器 本节我们先会来复习一下java.util.concurrent下面的一些并发容器,然后再会来简单看一下各种同步器. ConcurrentHashMa ...
- Java高并发编程:Copy-On-Write容器
Copy-On-Write简称COW,是一种用于程序设计中的优化策略.其基本思路是,从一开始大家都在共享同一个内容,当某个人想要修改这个内容的时候,才会真正把内容Copy出去形成一个新的内容然后再改, ...
- java高并发(十二)并发容器J.U.C
并发容器是JDK提供的一个包名:java.util.concurrent ArrayList -> CopyOnWriteArrayList CopyOnWriteArrayList是线程安全的 ...
- java高并发(十一)同步容器
上面一节我们介绍了ArrayList.HashSet.HashMap这些容器都是非线程安全的.如果有多个线程并发访问这些容器时,就会触发线程安全问题.因此在编写程序的时候,必须要求开发人员手动的在任何 ...
- Java多线程之并发容器(五)
1.hashtable和vector 它们是支持并发操作的并发容器,hashtable只不过是在hashmap的基础上,所有的方法上都加上synchronized关键字,vector在ArrayLis ...
最新文章
- linux扩容家目录,linux 根目录扩容
- 重构路上遇到的一些兼容性问题
- JavaWeb--MVC案例1-------(4)删除
- 华为fussioncompute上添加nexentastor作为IPSAN
- iOS-- pod常用命令
- android 电视关闭动画,Activity 展开和关闭动画
- WebHubBot 网络爬虫
- php100网站怎么了
- Axure RP8下载以及注册
- git 小乌龟 推送代码到gitee
- 快速理解色彩搭配的三个配色知识
- t600显卡和p620哪个好
- 计算机科学管理学专业大学排名,2020管理科学专业大学排名
- [Contrastive Learning] Improving Contrastive Learning by Visualizing Feature Transformation
- RS码FEC机制的实现方法(基于Luigi Rizzo的代码)
- ipad怎么分屏方法
- jquery项目实战——爱创课堂专业前端培训
- 【Flink】 is not serializable. The object probably contains or references non serializable fields
- 处女项目后关于IC验证经验的总结
- 求100以内的质数(Java版定义法、break优化,Math.sqrt()优化)
热门文章
- 别人的4G网总是比你快?只需这样设置一下,网速就能变快许多
- 【用HTML5来玩读心术】游戏很简单,但是挺有意思,分享给大家
- Codeforces Round #693 (Div. 3)G. Moving to the Capital
- html 百度语音合成,百度语音合成
- Java-增强io-缓冲流、转换流、序列化流
- Ubuntu 下安装deb包命令
- 物联网云平台用到的那些基本协议
- Spring参考文档翻译01--目录
- 从十几台电脑到百万IT投资 CIO张宝杰谈主动出击
- 本次操作由于这台计算机的限制而被取消 win8,Win8提示本次操作由于这台计算机的限制而被取消...