并发容器

引言

为了应对高并发过程中,数据一致性的问题,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常见并发容器相关推荐

  1. 谈谈java的并发容器、Queue

    目录 同步类容器 并发类容器 ConcurrentMap:支持高并发下线程安全. Copy-On-Write容器:最好在读多写少的情况下使用. 并发Queue 同步类容器 同步类容器是线程安全的. / ...

  2. Java集合之并发容器

    一:java中的并发容器总结 JDK提供的这些容器大部分在 java.util.concurrent 包中. ConcurrentHashMap: 线程安全的HashMap CopyOnWriteAr ...

  3. 探索JAVA并发 - 并发容器全家福!

    作者:acupt,专注Java,架构师社区合伙人! 14个并发容器,你用过几个? 不考虑多线程并发的情况下,容器类一般使用ArrayList.HashMap等线程不安全的类,效率更高.在并发场景下,常 ...

  4. java 头尾 队列_探索JAVA并发 - 并发容器全家福

    14个并发容器,你用过几个? 不考虑多线程并发的情况下,容器类一般使用ArrayList.HashMap等线程不安全的类,效率更高.在并发场景下,常会用到ConcurrentHashMap.Array ...

  5. 和朱晔一起复习Java并发(五):并发容器和同步器

    和朱晔一起复习Java并发(五):并发容器和同步器 本节我们先会来复习一下java.util.concurrent下面的一些并发容器,然后再会来简单看一下各种同步器. ConcurrentHashMa ...

  6. Java高并发编程:Copy-On-Write容器

    Copy-On-Write简称COW,是一种用于程序设计中的优化策略.其基本思路是,从一开始大家都在共享同一个内容,当某个人想要修改这个内容的时候,才会真正把内容Copy出去形成一个新的内容然后再改, ...

  7. java高并发(十二)并发容器J.U.C

    并发容器是JDK提供的一个包名:java.util.concurrent ArrayList -> CopyOnWriteArrayList CopyOnWriteArrayList是线程安全的 ...

  8. java高并发(十一)同步容器

    上面一节我们介绍了ArrayList.HashSet.HashMap这些容器都是非线程安全的.如果有多个线程并发访问这些容器时,就会触发线程安全问题.因此在编写程序的时候,必须要求开发人员手动的在任何 ...

  9. Java多线程之并发容器(五)

    1.hashtable和vector 它们是支持并发操作的并发容器,hashtable只不过是在hashmap的基础上,所有的方法上都加上synchronized关键字,vector在ArrayLis ...

最新文章

  1. linux扩容家目录,linux 根目录扩容
  2. 重构路上遇到的一些兼容性问题
  3. JavaWeb--MVC案例1-------(4)删除
  4. 华为fussioncompute上添加nexentastor作为IPSAN
  5. iOS-- pod常用命令
  6. android 电视关闭动画,Activity 展开和关闭动画
  7. WebHubBot 网络爬虫
  8. php100网站怎么了
  9. Axure RP8下载以及注册
  10. git 小乌龟 推送代码到gitee
  11. 快速理解色彩搭配的三个配色知识
  12. t600显卡和p620哪个好
  13. 计算机科学管理学专业大学排名,2020管理科学专业大学排名
  14. [Contrastive Learning] Improving Contrastive Learning by Visualizing Feature Transformation
  15. RS码FEC机制的实现方法(基于Luigi Rizzo的代码)
  16. ipad怎么分屏方法
  17. jquery项目实战——爱创课堂专业前端培训
  18. 【Flink】 is not serializable. The object probably contains or references non serializable fields
  19. 处女项目后关于IC验证经验的总结
  20. 求100以内的质数(Java版定义法、break优化,Math.sqrt()优化)

热门文章

  1. 别人的4G网总是比你快?只需这样设置一下,网速就能变快许多
  2. 【用HTML5来玩读心术】游戏很简单,但是挺有意思,分享给大家
  3. Codeforces Round #693 (Div. 3)G. Moving to the Capital
  4. html 百度语音合成,百度语音合成
  5. Java-增强io-缓冲流、转换流、序列化流
  6. Ubuntu 下安装deb包命令
  7. 物联网云平台用到的那些基本协议
  8. Spring参考文档翻译01--目录
  9. 从十几台电脑到百万IT投资 CIO张宝杰谈主动出击
  10. 本次操作由于这台计算机的限制而被取消 win8,Win8提示本次操作由于这台计算机的限制而被取消...