什么是阻塞队列
阻塞队列是一个支持两个附加操作的队列,支持阻塞的插入和移除方法。
- 阻塞的插入:当阻塞队列满的时候,会阻止其他线程插入元素,直到队列不满时,才可以继续插入
- 阻塞的移除:当阻塞队列不为空时,可以移除元素。当队列为空时,获取元素的线程会等到阻塞队列不为空时再获取元素。
抛出异常
当队列满的时候,在往里面插入元素会抛出illegalStateException异常,如果队列为空时,获取线程还有获取元素就会抛出NoSuchElementException异常
返回特殊值
往队列插入元素是,返回是否插入成功,成功返回true。
如果是移除方法,会玩队列移除一个元素,如果没有元素被移除则返回null
一直阻塞
如果阻塞队列满的时候,生产者的线程向队列里面put元素,就会一直被阻塞,直到队列为空或者响应中断。
如果阻塞队列空的时候,消费者的线程向队列里面take元素,就会一直被阻塞,直到队列不为空。
超时退出
当生产者的线程一直被阻塞的时候,可以设置一个时间。如果到达时间还处于阻塞状态就会退出。
生产者 put 插入元素 offer返回特殊值
消费者 take 移除元素 poll 返回特殊值
Java中的阻塞队列
- ArrayBlockingQueue 数组结构组成的有界阻塞队列
- LinkedBlockingQueue 链表结构组成的有界阻塞队列
- PriorityBlockingQueue 支持优先级排序的无界阻塞队列
- DelayQueue 支持优先级队列组成的的无界阻塞队列
- SynchronousQueue 不储存元素的阻塞队列
- LinkedTransferQueue 链表结构组成的无界阻塞队列
- LinkedBlockingDeque 链表结构组成的双向阻塞队列
1、ArrayBlockingQueue 是一个数组结构组成的有界阻塞对了,按照FIFO(先进先出)的原则对元素进行排序。
但是默认情况ArrayBlockingQueue不保证线程的公平访问。不一定先阻塞的线程最先脱离阻塞状态。当队列可用的时候,所以线程都会争夺使用权。类似公平锁和非公平锁一样。
2、LinkedBlockingQueue 是一个链表结构的有界阻塞队列。也是FIFO原则对元素排序。他的默认长度和最大长度都是Integer.MAX_VALUE。
3、PriorityBlockingQueue 是一个保证优先级的队列,但是不能保证同优先级的元素的顺序。是按照升序就行排列的。可以自定义compareTo()指定排序规则。
4、DelayQueue 是一个支持延时获取元素的无界队列。队列是用priorityBlockingQueue实现的。队列的元素必须实现Delayed接口。在创建元素队列的时候指定要多久才可以获取当前元素。只要到了延时的时间后才可以获取队列。
一般应用在一下场景:
缓冲系统的设计:用DelayQueue设置缓存元素的有效期,一个线程循环的查询DelayQueue,当能获取到的时候,则代表过期
定时任务调度:用DelayQueue保存当前任务执行的时间,一旦到了时间就会执行任务。TimerQueue就是使用DelayQueue实现的。
5、SynchronousQueue 是一个不存储元素的队列,所以每当生产者put的时候就必须等待消费者take一起进行。put和take一起进行,所以不存储元素。synchronoousQueue可以提供公平队列。默认是不公平队列。
6、LinkedTransferQueue 是一个由链表组成的无界阻塞TransferQueue队列,比较其他队列他就多了2个方法
(1)、transfer : 如果当前有消费者正在等take的元素。transfer方法可以把生产者put的元素立即给当前消费者。如果没有消费者在等待接收元素,transfer方法会把元素放在tail节点,等到消费者获取后返回。
(2)、tryTransfer:比较transfer就是不会等待,立即放回。相当于试探有无消费者需要take当前元素。
7、LinkedBlockingDeque 是由链表组成的双向阻塞队列。双向队列代表可以从两端都插入或移出元素。多线程队列的话就减小了一半的竞争。所以也多了许多方法,通过First和Last判断是从第一个元素还是最后一个元素。
本文参考《java并发编程的意思》