Java的堵塞队列BlockingQueue详解
作者:缘来如此09
一、简介
阻塞队列(BlockingQueue)是一个支持两个附加操作的队列。
这两个附加的操作支持阻塞的插入和移除方法。
1)支持阻塞的插入方法:意思是当队列满时,队列会阻塞插入元素的线程,直到队列不满。
2)支持阻塞的移除方法:意思是在队列为空时,获取元素的线程会等待队列变为非空。
阻塞队列常用于生产者和消费者的场景,生产者是向队列里添加元素的线程,消费者是从队列里取元素的线程。
阻塞队列就是生产者用来存放元素、消费者用来获取元素的容器。
二、BlockingQueue接口提供的方法
1.异常:
是指当阻塞队列满时候,再往队列里插入元素,会抛出IllegalStateException("Queuefull")异常。当队列为空时,从队列里获取元素时会抛出NoSuchElementException异常。
2.返回特殊值:
插入方法会返回是否成功,成功则返回true。移除方法,则是从队列里拿出一个元素,如果没有则返回null
3.一直阻塞:
当阻塞队列满时,如果生产者线程往队列里put元素,队列会一直阻塞生产者线程,直到拿到数据,或者响应中断退出。当队列空时,消费者线程试图从队列里take元素,队列也会阻塞消费者线程,直到队列可用。
4.超时退出:
当阻塞队列满时,队列会阻塞生产者线程一段时间,如果超过一定的时间,生产者线程就会退出。
BlockingQueue接口源码
public interface BlockingQueue<E> extends Queue<E> { //将给定元素设置到队列中,如果设置成功返回true, 否则抛出异常。如果是往限定了长度的队列中设置值,推荐使用offer()方法。 boolean add(E e); //将给定的元素设置到队列中,如果设置成功返回true, 否则返回false. e的值不能为空,否则抛出空指针异常。 boolean offer(E e); //将元素设置到队列中,如果队列中没有多余的空间,该方法会一直阻塞,直到队列中有多余的空间。 void put(E e) throws InterruptedException; //将给定元素在给定的时间内设置到队列中,如果设置成功返回true, 否则返回false. boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException; //从队列中获取值,如果队列中没有值,线程会一直阻塞,直到队列中有值,并且该方法取得了该值。 E take() throws InterruptedException; //在给定的时间里,从队列中获取值,如果没有取到会抛出异常。 E poll(long timeout, TimeUnit unit) throws InterruptedException; //获取队列中剩余的空间。 int remainingCapacity(); //从队列中移除指定的值。 boolean remove(Object o); //判断队列中是否拥有该值。 public boolean contains(Object o); //将队列中值,全部移除,并发设置到给定的集合中。 int drainTo(Collection<? super E> c); //指定最多数量限制将队列中值,全部移除,并发设置到给定的集合中。 int drainTo(Collection<? super E> c, int maxElements); }
三、Java里的阻塞队列
JDK提供了7个阻塞队列,如下。
1.ArrayBlockingQueue是一个用数组实现的有界阻塞队列,此队列按照先进先出(FIFO)的原则对元素进行排序。支持公平锁和非公平锁。
【注:每一个线程在获取锁的时候可能都会排队等待,如果在等待时间上,先获取锁的线程的请求一定先被满足,那么这个锁就是公平的。反之,这个锁就是不公平的。公平的获取锁,也就是当前等待时间最长的线程先获取锁】
2.LinkedBlockingQueue
LinkedBlockingQueue:一个由链表结构组成的有界队列,此队列的长度为Integer.MAX_VALUE。此队列按照先进先出的顺序进行排序
3.PriorityBlockingQueue
一个支持线程优先级排序的无界队列,默认自然序进行排序,也可以自定义实现compareTo()方法来指定元素排序规则,不能保证同优先级元素的顺序。
4.DelayQueue
一个实现PriorityBlockingQueue实现延迟获取的无界队列,在创建元素时,可以指定多久才能从队列中获取当前元素。只有延时期满后才能从队列中获取元素。(DelayQueue可以运用在以下应用场景:
1.缓存系统的设计:可以用DelayQueue保存缓存元素的有效期,使用一个线程循环查询DelayQueue,一旦能从DelayQueue中获取元素时,表示缓存有效期到了。
2.定时任务调度。使用DelayQueue保存当天将会执行的任务和执行时间,一旦从DelayQueue中获取到任务就开始执行,从比如TimerQueue就是使用DelayQueue实现的。)
5.SynchronousQueue
一个不存储元素的阻塞队列,每一个put操作必须等待take操作,否则不能添加元素。支持公平锁和非公平锁。SynchronousQueue的一个使用场景是在线程池里。Executors.newCachedThreadPool()就使用了SynchronousQueue,这个线程池根据需要(新任务到来时)创建新的线程,如果有空闲线程则会重复使用,线程空闲了60秒后会被回收。
6.LinkedTransferQueue
一个由链表结构组成的无界阻塞队列,相当于其它队列,LinkedTransferQueue队列多了transfer和tryTransfer方法。
7.LinkedBlockingDeque
一个由链表结构组成的双向阻塞队列。队列头部和尾部都可以添加和移除元素,多线程并发时,可以将锁的竞争最多降到一半。
到此这篇关于Java的堵塞队列BlockingQueue详解的文章就介绍到这了,更多相关BlockingQueue堵塞队列内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!