1:阻塞队列首先是一个队列,有先进先出,后进后出的原则
2:阻塞队列非常符合生产者消费者模式,生产者将生产的物品放入阻塞队列,如果阻塞队列满了就放 不进去,生产者的线程就会阻塞等待,消费者从阻塞队列中取出,如果没有数据的话也会进入阻塞状 态,进入等待;
3:如果没有阻塞队列的话,可能多个生产者线程不断的生产,但是消费者并没有去消费,就浪费了资源,也可能消费者一直去消费,但是没有东西消费;
阻塞队列的继承结构如下
主要有俩个实现类
ArrayBlockingQueue: 底层是数组,有界的,可以在创建的时候指定阻塞队列的大小
LinkedBlockingQueue: 底层是链表,无界.但不是真正的无界,最大为int的最大值
先上代码
/**
* 生产者类
*/
public class Cooker implements Runnable {
private ArrayBlockingQueue<String> arrayBlockingQueue;
public Cooker(ArrayBlockingQueue<String> arrayBlockingQueue) {
this.arrayBlockingQueue = arrayBlockingQueue;
}
public Cooker() {
}
@Override
public void run() {
while (true) {
try {
arrayBlockingQueue.put("生产的物品");
System.out.println("生产的物品放入阻塞队列-------");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* 消费者类
*/
public class Consumer implements Runnable {
private ArrayBlockingQueue<String> arrayBlockingQueue;
public Consumer(ArrayBlockingQueue<String> arrayBlockingQueue) {
this.arrayBlockingQueue = arrayBlockingQueue;
}
public Consumer() {
}
@Override
public void run() {
while (true) {
try {
String take = arrayBlockingQueue.take();
Thread.sleep(5000);
System.out.println("消费者正在消费---------");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class TestDemo {
public static void main(String[] args) {
// 指定一个大小为1的阻塞队列
ArrayBlockingQueue<String> bd = new ArrayBlockingQueue<>(1);
Consumer consumer = new Consumer(bd);
Cooker cooker = new Cooker(bd);
Thread c = new Thread(cooker);
Thread f = new Thread(consumer);
f.start();
c.start();
}
}
运行结果
这里就可以看到生产者生产一次,消费者就消费一次
BlockingQueue中的核心方法
//将给定元素设置到队列中,如果设置成功返回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);
}
阻塞队列实际上是使用了Condition来模拟线程间协作。
Condition是用来替代传统的Object的wait()、notify()实现线程间的协作,相比使用Object的wait()、notify(),使用Condition的await()、signal()这种方式更加安全和高效。
这是ArrayBlockingQueue的关于put和take方法的小部分源码源码
private final Condition notEmpty;
private final Condition notFull;
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();
}
}
如果需要了解的更深入,就继续学习这个大佬的文章
北极猩球Java 阻塞队列–BlockingQueue
越学越觉得自己越无知,如果有错误,请指出,谢谢