打赏

Java 并发系列之七:java 阻塞队列(7个)

 

1. 基本概念

2. 实现原理

 

3. ArrayBlockingQueue

4. LinkedBlockingQueue

5. LinkedBlockingDeque

6. PriorityBlockingQueue

7. DelayQueue

8. SynchronousQueue

9. LinkedTransferQueue

10. 小总结

11. txt

  1 Java阻塞队列(7个)
  2     基本概念
  3         阻塞队列是一个支持两个附加操作的队列
  4         两个附加操作
  5             支持阻塞的插入方法
  6                 当队列满时,队列会阻塞插入元素的线程,直到队列不满
  7             支持阻塞的移除方法
  8                 当队列空时,队列会阻塞获取元素的线程,直到队列非空
  9         阻塞队列的4中处理方式
 10             抛出异常
 11                 定义
 12                     当队列满时,如果再往队列里插入元素,会抛出IllegalStateException
 13                     当队列空时,如果在从队列里移除元素,会抛出NoSuchElementException
 14                 具体方法
 15                     插入方法
 16                         add(e)
 17                     移除方法
 18                         remove()
 19                     检查方法
 20                         element()
 21             返回特殊值
 22                 定义
 23                     往队列插入元素时,会返回元素是否插入成功,成功返回true
 24                     从队列移除元素时,如果没有则会返回null
 25                 具体方法
 26                     插入方法
 27                         offer(e)
 28                     移除方法
 29                         poll()
 30                     检查方法
 31                         peek()
 32             一直阻塞
 33                 定义
 34                     当队列满时,如果生产者线程再往队列里put插入元素,队列会一直阻塞生产者线程,直到队列可用或者响应中断退出
 35                     当队列空时,如果消费者线程从队列里take移除元素,队列会阻塞住消费者线程,直到队列不为空
 36                 具体方法
 37                     插入方法
 38                         put(e)
 39                     移除方法
 40                         take()
 41                     检查方法
 42                         不可用
 43             超时退出
 44                 定义
 45                     当队列满时,如果生产者线程再往队列里插入元素,队列会阻塞生产者线程一段时间,超过了指定的时间,生产者线程就会退出
 46                 具体方法
 47                     插入方法
 48                         offer(e, time, unit)
 49                     移除方法
 50                         poll( time, unit )
 51                     检查方法
 52                         不可用
 53             注意: 如果是无界阻塞队列, 队列不可能出现满的情况,使用put或offer方法永远不会被阻塞,而且使用offer方法时,永远返回true
 54         应用场景
 55             生产者消费者场景
 56             阻塞队列就是生产者用来存放元素,消费者用来获取元素的容器
 57     实现原理
 58         使用通知模式
 59         当生产者往满的队列里添加元素时会阻塞住生产者,当消费者消费了一个队列中的元素后,会通知生产者当前队列可用
 60     小总结
 61         一个抽象类
 62             AbstractQueue,改类在Queue接口中扮演着非常重要的作用,该类提供了对queue操作的骨干实现
 63         一个接口
 64             BlockingQueue继承java.util.Queue为阻塞队列的核心接口,提供了在多线程环境下的出列、入列操作,作为使用者,则不需要关心队列在什么时候阻塞线程,什么时候唤醒线程,所有一切均由BlockingQueue来完成。
 65         七个阻塞队列
 66             ArrayBlockingQueue
 67                 一个由数组组成的有界阻塞队列
 68             LinkedBlockingQueue
 69                 一个由链表组成的有界阻塞队列
 70             LinkedBlockingDeque
 71                 一个由链表组成的双向阻塞队列
 72             PriorityBlockingQueue
 73                 一个支持优先级排序的无界阻塞队列
 74             DelayQueue
 75                 一个使用优先级队列实现的无界阻塞队列
 76             SynchronousQueue
 77                 一个不存储元素的阻塞队列
 78             LinkedTransferQueue
 79                 一个由链表组成的无界阻塞队列
 80                     即可以像其他的BlockingQueue一样有容量又可以像SynchronousQueue一样不会锁住整个队列
 81             有界
 82             对读或者写都是锁上整个队列,在并发量大的时候,各种锁是比较耗资源和耗时间的
 83     LinkedTransferQueue
 84         特性
 85             一个由链表组成的无界阻塞队列,FIFO
 86             即可以像其他的BlockingQueue一样有容量又可以像SynchronousQueue一样不会锁住整个队列
 87             相对于其他的阻塞队列,LinkedTransferQueue多了tryTransfer和transfer方法
 88             LinkedTransferQueue是一个聪明的队列。它是ConcurrentLinkedQueue(无界非阻塞队列)、SynchronousQueue (公平模式下)、无界的LinkedBlockingQueues等的超集。
 89             LinkedTransferQueue采用一种预占模式。什么意思呢?有就直接拿走,没有就占着这个位置直到拿到或者超时或者中断。即消费者线程到队列中取元素时,如果发现队列为空,则会生成一个null节点,然后park住等待生产者。后面如果生产者线程入队时发现有一个null元素节点,这时生产者就不会入列了,直接将元素填充到该节点上,唤醒该节点的线程,被唤醒的消费者线程拿东西走人。
 90         Node节点
 91             isData:表示该节点是存放数据还是获取数据
 92             item:存放数据,isData为false时,该节点为null,为true时,匹配后,该节点会置为null
 93             next:指向下一个节点
 94             waiter:park住消费者线程,线程就放在这里
 95         重要操作
 96             LinkedTransferQueue提供了add、put、offer三类方法,用于将元素插入队列中
 97             LinkedTransferQueue提供了poll、take方法用于出列元素
 98             transfer方法
 99                 如果当前有消费者正在等待接收元素,transfer可以把生产者传入的元素立刻传输给消费者
100 如果没有,会将元素存放在队列的tail节点,并等到该元素被消费者消费(CAS)了才返回
101             tryTransfer方法
102                 试探生产者传入的元素是否能直接传给消费者
103 如果没有消费者等待接受元素,则返回false
104             两者的区别是tryTransfer方法无论消费者是否接收,方法立即返回
105 transfer方法必须等到消费者消费了才返回
106     SynchronousQueue
107         特性
108             一个不存储元素的阻塞队列
109             SynchronousQueue没有容量。与其他BlockingQueue不同,SynchronousQueue是一个不存储元素的BlockingQueue。每一个put操作必须要等待一个take操作,否则不能继续添加元素,反之亦然。
110             因为没有容量,所以对应 peek, contains, clear, isEmpty … 等方法其实是无效的。例如clear是不执行任何操作的,contains始终返回false,peek始终返回null。
111             SynchronousQueue分为公平和非公平,默认情况下采用非公平性访问策略,当然也可以通过构造函数来设置为公平性访问策略(为true即可,FIFO)。
112             SynchronizedQueue的吞吐量高于LinkedBlockingQueue和ArrayBlockingQueue
113             若使用 TransferQueue, 则队列中永远会存在一个 dummy node
114         应用场景
115             传递性场景
116                 负责把生产者线程处理的数据直接传递给消费者线程
117                 生产者的线程和消费者的线程同步以传递某些信息、事件或者任务
118         内部类
119             Transferer
120                 Transferer为SynchronousQueue的内部类,它提供了一个方法transfer(),该方法定义了转移数据的规范
121             TransferQueue
122                 SynchronousQueue采用队列TransferQueue来实现公平性策略
123             TransferStack
124                 采用堆栈TransferStack来实现非公平性策略
125             TransferQueue、TransferStack继承Transferer
126 两种都是通过链表实现的,其节点分别为QNode,SNode
127         Exchanger 可能被视为 SynchronousQueue 的双向形式。
128             它提供一个同步点,用于进行线程间成对配对及交换数据,
129     DelayQueue
130         特性
131             一个使用优先级队列实现的无界阻塞队列,使用PriorityQueue来实现,延时获取
132             DelayQueue是一个支持延时获取元素的无界阻塞队列。里面的元素全部都是“可延期”的元素,列头的元素是最先“到期”的元素,如果队列里面没有元素到期,是不能从列头获取元素的,哪怕有元素也不行。也就是说只有在延迟期到时才能够从队列中取元素。
133             PriorityQueue作为一个容器,容器里面的元素都应该实现Delayed接口,在每次往优先级队列中添加元素时以元素的过期时间作为排序条件,最先过期的元素放在优先级最高。
134             与Exchanger有一拼
135         应用场景
136             缓存系统的设计
137                 可是用DelayQueue保存缓存元素的有效期,使用一个线程循环查询DelayQueue,一旦能从DelayQueue中获取元素时,表示缓存有效期到了
138             定时任务调度
139                 使用DelayQueue保存当天将会执行的任务和执行时间,一旦从DelayQueue中获取到任务就开始执行,比如TimerQueue就是使用DelayQueue实现的。
140         内部结构|重要参数
141             可重入锁ReentrantLock
142             用于阻塞和通知的Condition对象
143             根据Delay时间排序的优先级队列:PriorityQueue
144             用于优化阻塞通知的线程元素leader,通过leader来减少不必要阻塞。
145         实现
146             继承Delay接口
147                 创建对象,初始化基础数据,time记录当前对象延迟到什么时候能用,sequenceNumber表示元素在队列中的先后顺序
148                 实现getDelay方法,该方法返回当前元素还需要延时多长时间,单位是纳秒
149                 实现compareTo方法来指定元素的顺序
150             实现延时阻塞队列
151                 当消费者线程从队列里获取元素时,如果元素没有达到延时时间,就阻塞当前线程
152         重要操作
153             offer
154                 offer(E e)就是往PriorityQueue中添加元素,同PriorityBlockingQueue,但是注意有一点如果当前元素的对首元素(优先级最高),leader设置为null,唤醒所有等待线程
155             take
156                 首先是获取对首元素,如果对首元素的延时时间 delay <= 0 ,则可以出对了,直接return即可。否则设置first = null,这里设置为null的主要目的是为了避免内存泄漏。如果 leader != null 则表示当前有线程占用,则阻塞,否则设置leader为当前线程,然后调用awaitNanos()方法超时等待。
157     PriorityBlockingQueue
158         特性
159             一个支持优先级排序的无界阻塞队列,支持优先级
160             PriorityBlockingQueue底层采用二叉堆来实现的,添加操作是添加到最后不断“上冒”,删除操作是删掉根将最后一个提到根不断“下掉”。
161             内部仍然采用可重入锁ReentrantLock来实现同步机制,但是这里只有一个notEmpty的Condition,因为无界队列,插入总是会成功,除非资源耗尽
162             默认情况下元素采用自然顺序升序排序,当然我们也可以通过构造函数来指定Comparator来对元素进行排序。需要注意的是PriorityBlockingQueue不能保证同优先级元素的顺序。
163         分类
164             - 最大堆
165                 - 父节点的键值总是大于或等于任何一个子节点的键值
166             - 最小堆
167                 - 父节点的键值总是小于或等于任何一个子节点的键值
168     LinkedBlockingDeque
169         特性
170             一个由链表组成的双向阻塞队列,LinkedBlockingDeque支持FIFO、FILO两种操作方式。
171             LinkedBlockingDeque底层实现机制是通过互斥锁ReentrantLock 来实现,notEmpty 、notFull 两个Condition做协调生产者、消费者问题。
172             LinkedBlockingDeque是可选容量的,在初始化时可以设置容量防止其过度膨胀,如果不设置,默认容量大小为Integer.MAX_VALUE。
173             多了一个操作队列的入口,在多线程同时入队时,减少了一般的竞争
174         内部类Node
175             E item;
176                     Node<E> prev;
177                     Node<E> next;
178         重要操作
179             入队
180                 putFirst(E e) :将指定的元素插入此双端队列的开头,必要时将一直等待可用空间。
181                 putLast(E e) :将指定的元素插入此双端队列的末尾,必要时将一直等待可用空间。
182             出队
183                 pollFirst():获取并移除此双端队列的第一个元素;如果此双端队列为空,则返回 null184                 pollLast():获取并移除此双端队列的最后一个元素;如果此双端队列为空,则返回 null185             其他
186                 LinkedBlockingDeque大部分方法都是通过linkFirst、linkLast、unlinkFirst、unlinkLast这四个方法来实现的,因为是双向队列,所以他们都是针对first、last的操作
187                 LinkedBlockingDeque 的add、put、offer、take、peek、poll系列方法都是通过调用XXXFirst,XXXLast方法。
188         应用
189             工作窃取模式中
190     LinkedBlockingQueue
191         特性
192             一个由链表组成的有界阻塞队列,该队列采用FIFO的原则对元素进行排序添加的。
193             LinkedBlockingQueue是通过互斥锁ReentrantLock 来实现,notEmpty 、notFull 两个Condition做协调生产者、消费者问题。
194             默认和最大长度是Integer.MAX_VALUE
195     ArrayBlockingQueue
196         特性
197             ArrayBlockingQueue,一个由数组实现的有界阻塞队列。该队列采用FIFO的原则对元素进行排序添加的。
198             ArrayBlockingQueue内部使用可重入锁ReentrantLock + Condition来完成多线程环境的并发操作。
199             ArrayBlockingQueue为有界且固定,其大小在构造时由构造函数来决定,确认之后就不能再改变了。
200             ArrayBlockingQueue支持对等待的生产者线程和使用者线程进行排序的可选公平策略,但是在默认情况下不保证线程公平的访问,在构造时可以选择公平策略(fair = true)。公平性通常会降低吞吐量,但是减少了可变性和避免了“不平衡性”。
201         重要参数
202             items,一个定长数组,维护ArrayBlockingQueue的元素
203             takeIndex,int,为ArrayBlockingQueue队首位置
204             putIndex,int,ArrayBlockingQueue队尾位置
205             count,元素个数
206             lock,锁,ArrayBlockingQueue出列入列都必须获取该锁,两个步骤公用一个锁
207             notEmpty,出列条件:不空
208             notFull,入列条件:不满
209         重要操作
210             入队
211                 add(E e) :将指定的元素插入到此队列的尾部(如果立即可行且不会超过该队列的容量),在成功时返回 true,如果此队列已满,则抛出 IllegalStateException
212                 offer(E e) :将指定的元素插入到此队列的尾部(如果立即可行且不会超过该队列的容量),在成功时返回 true,如果此队列已满,则返回 false
213                 offer(E e, long timeout, TimeUnit unit) :将指定的元素插入此队列的尾部,如果该队列已满,则在到达指定的等待时间之前等待可用的空间
214                 put(E e) :将指定的元素插入此队列的尾部,如果该队列已满,则等待可用的空间
215             出队
216                 poll() :获取并移除此队列的头,如果此队列为空,则返回 null
217                 poll(long timeout, TimeUnit unit) :获取并移除此队列的头部,在指定的等待时间前等待可用的元素(如果有必要)
218                 remove(Object o) :从此队列中移除指定元素的单个实例(如果存在)
219                 take() :获取并移除此队列的头部,在元素变得可用之前一直等待(如果有必要)
View Code

 

12. 参考网址

  1. 参考来源:http://cmsblogs.com/wp-content/resources/img/sike-juc.png
  2. 《Java并发编程的艺术》_方腾飞PDF 提取码:o9vr
  3. http://ifeve.com/the-art-of-java-concurrency-program-1/
  4. Java并发学习系列-绪论
  5. Java并发编程实战
  6. 死磕 Java 并发精品合集
posted @ 2019-07-17 11:31  海米傻傻  阅读(539)  评论(0编辑  收藏  举报