JUC编程:自定义实现有界阻塞队列

it2022-05-05  230

看了各种博文,觉得还是自己看看源码,理解完后自己实现一遍最好

1:BlockingQueue继承关系

  java.util.concurrent 包里的 BlockingQueue是一个接口, 继承Queue接口,Queue接口继承 Collection

BlockingQueue :不接受 null 元素。试图 add、put 或 offer 一个 null 元素时,某些实现会抛出 NullPointerException。null 被用作指示 poll 操作失败的警戒值。

BlockingQueue: 可以是限定容量的。它在任意给定时间都可以有一个 remainingCapacity,超出此容量,便无法无阻塞地 put 附加元素。没有任何内部容量约束的 BlockingQueue 总是报告Integer.MAX_VALUE 的剩余容量。

BlockingQueue :实现主要用于生产者-使用者队列,但它另外还支持 Collection 接口。因此,举例来说,使用 remove(x) 从队列中移除任意一个元素是有可能的。然而,这种操作通常不 会有效执行,只能有计划地偶尔使用,比如在取消排队信息时。

BlockingQueue :实现是线程安全的。所有排队方法都可以使用内部锁或其他形式的并发控制来自动达到它们的目的。然而,大量的 Collection 操作(addAll、containsAll、retainAll 和removeAll)没有 必要自动执行,除非在实现中特别说明。因此,举例来说,在只添加了 c 中的一些元素后,addAll(c) 有可能失败(抛出一个异常)。

2 BlockingQueue理解

一个线程往里边放,另外一个线程从里边取的一个 BlockingQueue。

 一个线程将会持续生产新对象并将其插入到队列之中,直到队列达到它所能容纳的临界点。也就是说,它是有限的。如果该阻塞队列到达了其临界点,负责生产的线程将会在往里边插入新对象时发生阻塞。它会一直处于阻塞之中,直到负责消费的线程从队列中拿走一个对象。

 负责消费的线程将会一直从该阻塞队列中拿出对象。如果消费线程尝试去从一个空的队列中提取对象的话,这个消费线程将会处于阻塞之中,直到一个生产线程把一个对象丢进队列。

3 自定义实现BlockingQueue

import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; /** * 自定义实现有界阻塞队列 * 数组实现 * Created by HH on 2019/7/17. */ public class MyArrayBlockingQueue<T> { /** * 队列实现 */ private Object[] items; /** * 元素个数 */ private int count; /** * 准备插入位置 */ private int putIndex = 0; /** * 准备移除位置 */ private int removeIndex = 0; ReentrantLock lock = new ReentrantLock(true); /** * 队列满情况 */ Condition notFull = lock.newCondition(); /** * 队列为空情况 */ Condition notEmpty = lock.newCondition(); public MyArrayBlockingQueue(int size) { this.items = new Object[size]; } /** * 进队 插入最后一个元素位置 * * @param t * @return * @throws InterruptedException */ public void enqueue(T t) throws InterruptedException { //检查是否为空 checkNull(t); //获取锁 lock.lock(); try { //已经满了 则发生阻塞 无法继续插入 while (items.length == count) { System.out.println(t + "进队阻塞,当前数据量" + count); notFull.await(); } items[putIndex] = t; System.out.println("入队:" + t); if (++putIndex == items.length) { putIndex = 0; } count++; notEmpty.signal(); } finally { lock.unlock(); } } /** * 出队 最后一个元素 * * @return */ public Object dequeue() throws InterruptedException { lock.lock(); Object o; try { while (count == 0) { System.out.println("出队阻塞,当前数据量" + count); notEmpty.await(); } o = this.items[removeIndex]; this.items[removeIndex] = null; System.out.println("出队:" + o); if (++removeIndex == items.length) { removeIndex = 0; } count--; notFull.signal(); } finally { lock.unlock(); } return o; } private void checkNull(T t) { if (t == null) { throw new NullPointerException(); } } public static void main(String[] args) { MyArrayBlockingQueue<Object> objectMyArrayBlockingQueue = new MyArrayBlockingQueue<>(2); ExecutorService executorService = Executors.newFixedThreadPool(10); for (int i = 0; i < 10; i++) { int data = i; executorService.execute(new Runnable() { @Override public void run() { try { objectMyArrayBlockingQueue.enqueue(data); } catch (InterruptedException e) { e.printStackTrace(); } } }); } for (int i = 0; i < 10; i++) { executorService.execute(new Runnable() { @Override public void run() { try { objectMyArrayBlockingQueue.dequeue(); } catch (InterruptedException e) { e.printStackTrace(); } } }); } } }

输出效果如下:

 

这里采用公平锁,看控制台输出就可以看出


最新回复(0)