谈谈阻塞队列以及阻塞队列四种⽅法类型
在多线程领域,所谓的阻塞,在某些情况下会挂起线程即阻塞,⼀旦满⾜某条件时,被挂起的线程⼜会⾃动被唤醒。队列的数据结构⼤家并不陌⽣,先进先出,先到先得,什么是阻塞队列呢,顾名思义,⾸先它是⼀个队列,当阻塞队列是空时,从队列中获取元素的操作将会被阻塞,当阻塞队列是满时,往队列⾥添加元素的操作将会被阻塞,那为什么需要阻塞队列呢,好处就是我们不需要关⼼什么时候需要阻塞线程,什么时候需要唤醒线程,,在concurrent包发布之前,线程的控制,需要程序员⾃⼰来通过synchronized来控制线程的阻塞(wait)和唤醒(notify,notifyAll),当concurrent包发布之后这⼀切阻塞线程都为我们⼀⼿包办了,那阻塞队列有哪些种类呢。
ArrayBlockingQueue 是⼀个基于数组的有界阻塞队列,次队列按FIFO(先进先出)原则对元素进⾏排序
LinkedBlockingQueue 是⼀个基于链表结构的有界(默认值是Integer.MAX_VALUE)阻塞队列,次队列按FIFO(先进先出)排序元素,吞吐量通常要⾼于ArrayBlockQueue
SynchronousQuere是⼀个不存储元素的阻塞队列,每个插⼊操作必须等到另⼀个线程调⽤移除操作,否则插⼊操作⼀直处于阻塞状态,吞吐量通常要⾼于前两种
PriorityBlockingQueue ⽀持优先级排序的⽆界阻塞队列
DelayQueue 使⽤优先级队列实现的延迟⽆界阻塞队列
LinkedTransferQueue 有链表结构组成的⽆界阻塞队列
LinkedBlockingDeque 有链表结构组成的双向阻塞队列
以后的⽂章我们着重讲解ArrayBlockingQueue,LinkedBlockingQueue和SynchronousQuere,因为后边说到线程池的时候主要是这三个。
接下来,我们按照下边的表来⼀个⼀个介绍阻塞线程的⽅法类型。
⽅法类型抛出异常特殊值阻塞超时
插⼊add offer put offer
移除remove poll take poll
检查element peek不可⽤不可⽤
先来看,抛出异常的add,remove,和element的阻塞队列的例⼦
import urrent.ArrayBlockingQueue;
import urrent.BlockingQueue;
public class BlockingQueueDemo {
public static void main(String[] args) throws Exception {
BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<String>(3);
// println(blockingQueue.add("d"));
// ve());
}
}
当add⽅法的注释放开的时候,会抛出下边的错误。
true
true
true
Exception in thread "main" java.lang.IllegalStateException: Queue full
at java.ba/java.util.AbstractQueue.add(AbstractQueue.java:98)
at java.ba/urrent.ArrayBlockingQueue.add(ArrayBlockingQueue.java:326)
at BlockingQueueDemo.main(BlockingQueueDemo.java:12)
当remove⽅法的注释放开的时候,会抛出下边的错误,说明add⽅法,remove⽅法⼀⾔不和就抛出异常。
true
true
true
a
a
b
c
Exception in thread "main" java.util.NoSuchElementException
at java.ba/java.ve(AbstractQueue.java:117)
at BlockingQueueDemo.main(BlockingQueueDemo.java:19)
再来看,不抛出异常的offer,peek,和poll的阻塞队列的例⼦
import urrent.ArrayBlockingQueue;
import urrent.BlockingQueue;
public class BlockingQueueDemo {
public static void main(String[] args) throws Exception {
BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<String>(3);
支付英语println(blockingQueue.offer("d"));
}
}
从下边的执⾏结果来看,当往阻塞队列⾥追加元素的时候会返回fal,以及当从空的阻塞队列中删除元素的时候,会返回null,这样程序相⽐直接抛出异常会显得友好些。
true
触摸用英语怎么说true
true
fal
a
a
b
c
null
我们再来说说上表中第三种情况的put,take⽅法,阻塞,即不抛异常,也不返回结果,我们在看来看⼀个demo
import urrent.ArrayBlockingQueue;
import urrent.BlockingQueue;
public class BlockingQueueDemo {
public static void main(String[] args) throws Exception {
BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<String>(3);
blockingQueue.put("a");
blockingQueue.put("b");
blockingQueue.put("c");
淘宝网货到付款女装
//blockingQueue.put("d");
blockingQueue.take();
blockingQueue.take();外祖父母
blockingQueue.take();
小学生个人介绍//blockingQueue.take();
励志语言}
}
⾸先创建容量为3的阻塞队列,当3个元素加满的时候,在想往容器中追加元素的时候,阻塞队列会⼀直等待,take⽅法也是⼀样的,当阻塞队列为空的时候,在想从队列当中take元素时,也是会阻塞。
最后,我们看看第四种情况,带时间参数的阻塞队列。
import urrent.ArrayBlockingQueue;
import urrent.BlockingQueue;
import urrent.TimeUnit;
public class BlockingQueueDemo {
public static void main(String[] args) throws Exception {伊拉克战争
BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<String>(3);
}
}
从执⾏结果来看,设定阻塞时间后,在指定的时间内没有添加成功的话,会返回结果,不阻塞,相⽐阻塞的⽅法也得友好。
true
true
true
fal
阻塞队列以及阻塞队列的四种⽅法类型介绍到这⾥,实际的开发过程中,根据⾃⼰的业务场景来选择具体的⽅法类型,好的,下篇见。