队列什么时候会阻塞?
答:队满,无法写入元素,如果队列满了,就必须阻塞等待
如果队列是空的,必须等待插入元素
从下图可以看出blockingqueue与list和set是同级的接口
什么情况会使用阻塞队列?
多线程(A调用B,必须等B先执行,B没有执行完,A就会挂起或者等待)
线程池(出了弹性大小之外,一般会用一个队列去维护里面的大小)
学会使用队列
添加,移出
BlockingQueue的四组API
1、抛出异常
2、不会抛出异常
3、阻塞等待
4、超时等待
通过观察源码,我们会发现,add和remove是用offer 和poll 实现的,而element()的底层是用peek()实现的
add()/remove()
public boolean add(E e) {
if (offer(e))
return true;
else
throw new IllegalStateException("Queue full");
}
public E remove() {
E x = poll();
if (x != null)
return x;
else
throw new NoSuchElementException();
}
当插入元素超过队列容量,add抛出异常,当队列没有元素,但是执行了remove,会抛出异常
public static void test1()
{
ArrayBlockingQueue bq=new ArrayBlockingQueue(3);
System.out.println(bq.add(1));
System.out.println(bq.add("2"));
System.out.println(bq.add(3));
System.out.println(bq.add(4));
}
public static void test1()
{
ArrayBlockingQueue bq=new ArrayBlockingQueue(3);
System.out.println(bq.add(1));
System.out.println(bq.add("2"));
System.out.println(bq.add(3));
// System.out.println(bq.add(4));
System.out.println(bq.remove());
System.out.println(bq.remove());
System.out.println(bq.remove());
System.out.println(bq.remove());
}
offer()/poll()
public boolean offer(E e) {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lock();
try {
if (count == items.length)
return false;
else {
enqueue(e);
return true;
}
} finally {
lock.unlock();
}
}
public E poll() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return (count == 0) ? null : dequeue();
} finally {
lock.unlock();
}
}
当插入元素超过队列容量,offer返回false,当队列没有元素,但是执行了poll,会返回null
public static void test2() {
ArrayBlockingQueue bq=new ArrayBlockingQueue(3);
System.out.println(bq.offer(1));
System.out.println(bq.offer("2"));
System.out.println(bq.offer(3));
System.out.println(bq.offer(4));
}
public static void test2() {
ArrayBlockingQueue bq=new ArrayBlockingQueue(3);
System.out.println(bq.offer(1));
System.out.println(bq.offer("2"));
System.out.println(bq.offer(3));
System.out.println(bq.poll());
System.out.println(bq.poll());
System.out.println(bq.poll());
System.out.println(bq.poll());
}
put()/take()
public void put(E e) throws InterruptedException {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == items.length)
notFull.await();
enqueue(e);
} finally {
lock.unlock();
}
}
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0)
notEmpty.await();
return dequeue();
} finally {
lock.unlock();
}
}
可以看出,put take 没有返回值
public static void test3() throws InterruptedException {
ArrayBlockingQueue bq=new ArrayBlockingQueue(3);
bq.put(1);
bq.put(2);
bq.put(3);
bq.put(4);
}
可以看到,当插入元素超过队列容量,put会阻塞,当队列没有元素,但是执行了take,也会阻塞
可以看到take是有返回值的
public static void test3() throws InterruptedException {
ArrayBlockingQueue bq=new ArrayBlockingQueue(3);
bq.put(1);
bq.put(2);
bq.put(3);
System.out.println(bq.take());
System.out.println(bq.take());
System.out.println(bq.take());
System.out.println(bq.take());
}
可以看到阻塞了
/**
* 等待,阻塞(等待超时)
*/
public static void test4() throws InterruptedException {
// 队列的大小
ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
blockingQueue.offer("a");
blockingQueue.offer("b");
blockingQueue.offer("c");
// blockingQueue.offer("d",2,TimeUnit.SECONDS); // 等待超过2秒就退出
System.out.println("===============");
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll());
blockingQueue.poll(2,TimeUnit.SECONDS); // 等待超过2秒就退出
}
peek()/element()
public E peek() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return itemAt(takeIndex); // null when queue is empty
} finally {
lock.unlock();
}
}
public E element() {
E x = peek();
if (x != null)
return x;
else
throw new NoSuchElementException();
}
public static void test3() throws InterruptedException {
ArrayBlockingQueue bq=new ArrayBlockingQueue(3);
bq.put(1);
bq.put(2);
bq.put(3);
System.out.println(bq.take());
System.out.println(bq.take());
System.out.println(bq.element());
System.out.println(bq.peek());
}
狂神的代码
package com.kuang.bq;
import java.util.Collection;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeUnit;
public class Test {
public static void main(String[] args) throws InterruptedException {
test4();
}
/**
* 抛出异常
*/
public static void test1(){
// 队列的大小
ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
System.out.println(blockingQueue.add("a"));
System.out.println(blockingQueue.add("b"));
System.out.println(blockingQueue.add("c"));
// IllegalStateException: Queue full 抛出异常!
// System.out.println(blockingQueue.add("d"));
System.out.println("=-===========");
System.out.println(blockingQueue.element()); // 查看队首元素是谁
System.out.println(blockingQueue.remove());
System.out.println(blockingQueue.remove());
System.out.println(blockingQueue.remove());
// java.util.NoSuchElementException 抛出异常!
// System.out.println(blockingQueue.remove());
}
/**
* 有返回值,没有异常
*/
public static void test2(){
// 队列的大小
ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
System.out.println(blockingQueue.offer("a"));
System.out.println(blockingQueue.offer("b"));
System.out.println(blockingQueue.offer("c"));
System.out.println(blockingQueue.peek());
// System.out.println(blockingQueue.offer("d")); // false 不抛出异常!
System.out.println("============================");
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll()); // null 不抛出异常!
}
/**
* 等待,阻塞(一直阻塞)
*/
public static void test3() throws InterruptedException {
// 队列的大小
ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
// 一直阻塞
blockingQueue.put("a");
blockingQueue.put("b");
blockingQueue.put("c");
// blockingQueue.put("d"); // 队列没有位置了,一直阻塞
System.out.println(blockingQueue.take());
System.out.println(blockingQueue.take());
System.out.println(blockingQueue.take());
System.out.println(blockingQueue.take()); // 没有这个元素,一直阻塞
}
/**
* 等待,阻塞(等待超时)
*/
public static void test4() throws InterruptedException {
// 队列的大小
ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
blockingQueue.offer("a");
blockingQueue.offer("b");
blockingQueue.offer("c");
// blockingQueue.offer("d",2,TimeUnit.SECONDS); // 等待超过2秒就退出
System.out.println("===============");
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll());
blockingQueue.poll(2,TimeUnit.SECONDS); // 等待超过2秒就退出
}
}
同步队列
- 同步队列
- 和其他的BlockingQueue 不一样, SynchronousQueue 不存储元素
- put了一个元素,必须从里面先take取出来,否则不能在put进去值!
package com.kuang.bq;
import java.sql.Time;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
/**
* 同步队列
* 和其他的BlockingQueue 不一样, SynchronousQueue 不存储元素
* put了一个元素,必须从里面先take取出来,否则不能在put进去值!
*/
public class SynchronousQueueDemo {
public static void main(String[] args) {
BlockingQueue<String> blockingQueue = new SynchronousQueue<>(); // 同步队列
new Thread(()->{
try {
System.out.println(Thread.currentThread().getName()+" put 1");
blockingQueue.put("1");
System.out.println(Thread.currentThread().getName()+" put 2");
blockingQueue.put("2");
System.out.println(Thread.currentThread().getName()+" put 3");
blockingQueue.put("3");
} catch (InterruptedException e) {
e.printStackTrace();
}
},"T1").start();
new Thread(()->{
try {
TimeUnit.SECONDS.sleep(3);
System.out.println(Thread.currentThread().getName()+"=>"+blockingQueue.take());
TimeUnit.SECONDS.sleep(3);
System.out.println(Thread.currentThread().getName()+"=>"+blockingQueue.take());
TimeUnit.SECONDS.sleep(3);
System.out.println(Thread.currentThread().getName()+"=>"+blockingQueue.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
},"T2").start();
}
}