JAVA 并发编程之五:同步容器: ConcurrentHashMap/Set +CopyOnWriteArrayList + ArrayBlockingQueue

前言

1. 支持CAS的数据结构使用场景:
避免使用同时锁??:如: AtomicXXX、ConcurrentMap、CopyOnWriteList、ConcurrentLinkedQueue;

2. 阻塞队列:
a. 在BlockingQueue中,要使用put和take,而非offer和poll。
b. 如果要使用offer和poll,也是要使用带等待时间参数的offer和poll。
c. 使用drainTo批量获得其中的内容,能够减少锁的次数。
d. 使用BlockingQueue的时候,尽量不要使用从Queue继承下来的 方法,否则就失去了Blocking的特性了。

 

同步容器

解决并发情况下的容器线程安全问题的。给多线程环境准备一个线程安全的容器对象。线程安全的容器对象: Vector, Hashtable。线程安全容器对象,都是使用 synchronized 方法实现的。 
concurrent 包中的同步容器,大多数是使用系统底层技术实现的线程安全。类似 native。 Java8 中使用 CAS。

 

Map/Set 

ConcurrentHashMap/ConcurrentHashSet

底层哈希实现的同步 Map(Set)。效率高,线程安全。使用系统底层技术实现线程安全。量级较 synchronized 低。key 和 value 不能为 null。

ConcurrentSkipListMap/ConcurrentSkipListSet

底层跳表(SkipList)实现的同步 Map(Set)。有序,效率比 ConcurrentHashMap 稍低。

 

List

CopyOnWriteArrayList

写时复制集合。写入效率低,读取效率高。每次写入数据,都会创建一个新的底层数组。

 

Queue

ConcurrentLinkedQueue

基础链表同步队列。

LinkedBlockingQueue 
阻塞队列,队列容量不足自动阻塞,队列容量为 0 自动阻塞。

ArrayBlockingQueue 
底层数组实现的有界队列。自动阻塞。根据调用 API(add/put/offer)不同,有不同特性。 
当容量不足的时候,有阻塞能力。 
add 方法在容量不足的时候,抛出异常。 
put 方法在容量不足的时候,阻塞等待。 
offer 方法, 
单参数 offer 方法,不阻塞。容量不足的时候,返回 false。当前新增数据操作放弃。三参数 offer 方法(offer(value,times,timeunit)),容量不足的时候,阻塞 times 时长(单 
位为 timeunit),如果在阻塞时长内,有容量空闲,新增数据返回 true。如果阻塞时长范围 
内,无容量空闲,放弃新增数据,返回 false。

DelayQueue 
延时队列。根据比较机制,实现自定义处理顺序的队列。常用于定时任务。如:定时关机。

LinkedTransferQueue 
转移队列,使用 transfer 方法,实现数据的即时处理。没有消费者,就阻塞。

SynchronusQueue 
同步队列,是一个容量为 0 的队列。是一个特殊的 TransferQueue。必须现有消费线程等待,才能使用的队列。 
add 方法,无阻塞。若没有消费线程阻塞等待数据,则抛出异常。 
put 方法,有阻塞。若没有消费线程阻塞等待数据,则阻塞。

 

阻塞队列BlockingQueue的实现

BlockingQueue即阻塞队列,从阻塞这个词可以看出,在某些情况下对阻塞队列的访问可能会造成阻塞。被阻塞的情况主要有如下两种:

  1. 当队列满了的时候进行入队列操作
  2. 当队列空了的时候进行出队列操作
    因此,当一个线程对已经满了的阻塞队列进行入队操作时会阻塞,除非有另外一个线程进行了出队操作,当一个线程对一个空的阻塞队列进行出队操作时也会阻塞,除非有另外一个线程进行了入队操作。
    从上可知,阻塞队列是线程安全的。
    下面是BlockingQueue接口的一些方法:
操作 抛异常 特定值 阻塞 超时
插入 add(o) offer(o) put(o) offer(o, timeout, timeunit)
移除 remove(o) poll(o) take(o) poll(timeout, timeunit)
检查 element(o) peek(o)    

这四类方法分别对应的是:
1 . ThrowsException:如果操作不能马上进行,则抛出异常
2 . SpecialValue:如果操作不能马上进行,将会返回一个特殊的值,一般是true或者false
3 . Blocks:如果操作不能马上进行,操作会被阻塞
4 . TimesOut:如果操作不能马上进行,操作会被阻塞指定的时间,如果指定时间没执行,则返回一个特殊值,一般是true或者false
下面来看由阻塞队列实现的生产者消费者模型,这里我们使用take()和put()方法,这里生产者和生产者,消费者和消费者之间不存在同步,所以会出现连续生成和连续消费的现象

 

资料整理来自:https://juejin.im/entry/596343686fb9a06bbd6f888c

你可能感兴趣的:(Java,并发编程,Java,并发编程)