5.阻塞队列
发现队列Queue和List/Set平级!
阻塞队列的四组API:
方式
|
抛出异常
|
有返回值,不抛出异常
|
阻塞 等待
|
超时等待
|
添加
|
add
|
offer()
|
put()
|
offer
|
移除
|
remove
|
poll()
|
take()
|
poll
|
检测队首元素
|
element
|
peek()
|
1.抛出异常api检测:add/remove/element
重点1:创建一个容量为3的队列
ArrayBlockingQueue arrayBlockingQueue=new ArrayBlockingQueue<>(3);
arrayBlockingQueue.add(1);
arrayBlockingQueue.add(2);
arrayBlockingQueue.add(3);
重点2:往里放入多于容量的数据,此时会抛出异常:Exception in thread "main" java.lang.IllegalStateException: Queue full
arrayBlockingQueue.add(4);
重点3:移除元素-->输出1:发现队列的特点:先进先出
System.out.println(arrayBlockingQueue.remove());
移除指定的元素
arrayBlockingQueue.remove(2)
如果对队列中已经没有元素,再次调用arrayBlockingQueue.remove();
会报错:Exception in thread "main" java.util.NoSuchElementException
重点5:检测队首元素-->返回的是队首的元素!
System.out.println(arrayBlockingQueue.element());
2.返回boolean值,不抛出异常!offer/poll/peek
ArrayBlockingQueue arrayBlockingQueue=new ArrayBlockingQueue<>(3);
System.out.println(arrayBlockingQueue.offer(1));
System.out.println(arrayBlockingQueue.offer(2));
System.out.println(arrayBlockingQueue.offer(3));
重点1:使用offer标签添加元素,上述三条输出true,下面输出false,不会抛出异常!
System.out.println(arrayBlockingQueue.offer(4));
重点2:取出操作:
System.out.println(arrayBlockingQueue.poll());
System.out.println(arrayBlockingQueue.poll());
System.out.println(arrayBlockingQueue.poll());
System.out.println(arrayBlockingQueue.poll());
输出:不抛异常,取完后返回null
1
2
3
null
3.阻塞等待:put/take
ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue<>(3);
arrayBlockingQueue.put("1");
arrayBlockingQueue.put("2");
arrayBlockingQueue.put("3");
重点1:控制台会输出-->3放入成功,队列已满..
System.out.println("3放入成功,队列已满..");
重点2:会在此处阻塞,后续打印不会进行..
arrayBlockingQueue.put("4");
System.out.println("检测4是否可以放置成功!");
4.超时等待/offer/poll传入参数
ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue<>(3);
//重点1:传入参数(放入队列元素,超时时间,超时时间单位)
System.out.println(arrayBlockingQueue.offer(1, 2, TimeUnit.SECONDS));
System.out.println(arrayBlockingQueue.offer(2, 2, TimeUnit.SECONDS));
System.out.println(arrayBlockingQueue.offer(3, 2, TimeUnit.SECONDS));
System.out.println("3放入完成!");
System.out.println("准备放4,当前时间:"+ DateUtil.now());
System.out.println(arrayBlockingQueue.offer(4, 2, TimeUnit.SECONDS));
System.out.println("4插入执行结束:当前时间->"+DateUtil.now());
输出:
true
true
true
3放入完成!
准备放4,当前时间:2021-08-06 15:16:13
false
4插入执行结束:当前时间->2021-08-06 15:16:15
发现,出现问题后,不会抛出异常,会在插入出阻塞对应时间,再执行后续!
SynchronousQueue
一种阻塞队列,队列中只能存储一个元素,当这个元素被取出时,才能又放进去
方法:put/take
样例:
public class SynchronousQueueDemo {
public static void main(String[] args) {
//重点1:创建SynchronousQueue的队列
BlockingQueue<String> blockingQue = new SynchronousQueue<>();
new Thread(() -> {
for (int i = 0; i < 6; i++) {
try {
System.out.println(Thread.currentThread().getName() + "准备放入值...");
//重点2:SynchronousQueue队列里最多只能放一个元素后,这里会阻塞,直至消息被取出!
blockingQue.put(Thread.currentThread().getName() + "放入" + i);
System.out.println(Thread.currentThread().getName() + "放入值成功!");
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "放线程").start();
new Thread(() -> {
for (int i = 0; i < 6; i++) {
try {
System.out.println(Thread.currentThread().getName() + "准备取出值...");
System.out.println(Thread.currentThread().getName() + "-->取出:" + blockingQue.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "读线程").start();
}
}
输出:
放线程准备放入值...
读线程准备取出值...
读线程-->取出:放线程放入0
放线程放入值成功!
读线程准备取出值...
放线程准备放入值...
放线程放入值成功!
读线程-->取出:放线程放入1
读线程准备取出值...
放线程准备放入值...
放线程放入值成功!
读线程-->取出:放线程放入2
读线程准备取出值...
放线程准备放入值...
放线程放入值成功!
读线程-->取出:放线程放入3
读线程准备取出值...
放线程准备放入值...
读线程-->取出:放线程放入4
读线程准备取出值...
放线程放入值成功!
放线程准备放入值...
放线程放入值成功!
读线程-->取出:放线程放入5
结论发现:
SynchronousQueue队列中只能放入一个元素,当这个元素被取出时,才能放入第二个元素!