动手实现阻塞队列

源头

最近一直在看多线程和并发的知识,然后也看了线程池、阻塞队列等源码,想要造个轮子,来加深对阻塞队列源码的理解。

思路

  1. 阻塞队列的实现思路还是利用等待/唤醒机制的思路。
  2. 队列的实现使用双向链表LinkedList实现,因为队列是后进先出保证公平性,所以存元素就插入到队列的尾部,而取元素就从队列的头部取出元素。
  3. 队列的存取元素是在多线程的环境下,所有使用重入锁ReentrantLock实现。
  4. 队列满了,那么就让生产者等待,唤醒消费者。
  5. 队列空了,那么就让消费者等待,唤醒生产者、
  6. 如果队列满了,一直没有消费者消费,那么生产者就会一直阻塞。
  7. 如果队列空了,一直没有生产者生产,那么消费者就会一直阻塞。

实现

  • 测试:
public static void main(String[] args) {
	SimpleBlockingQueue<String> queue = new SimpleBlockingQueue<>(5);
	for (int i = 0; i < 10 ; i ++) {
		final int fi = i;
		Thread t1 = new Thread(() -> {
			System.out.println("=================== producer i = " + fi);
			try {
				queue.addByBlock(String.valueOf(fi));
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		});

		t1.start();
	}

	for (int j = 0 ; j < 1 ; j++) {
		Thread t2 = new Thread(() -> {
			try {
				String msg = queue.getByBlock();
				System.out.println("=================== consumer msg = " + msg);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		});

		t2.start();
	}
}
  • 核心实现
/**
 * 自定义简易版阻塞队列
 * @author sunpeiyu
 * @date 2023-05-17
 * @param <T>
 */
public class SimpleBlockingQueue<T> {
    // 双向链表存放元素
    private final LinkedList<T> mainList;
    // 多线程存取队列元素的锁
    private final ReentrantLock mainLock;
    // 存入元素的等待队列
    private final Condition produceCondition;
    // 取出元素的等待队列
    private final Condition consumeCondition;
    // 阻塞队列的长度(双向链表的长度)
    private final Integer queueSize;
    // 统计阻塞队列中元素个数
    private Integer count = 0;

    public SimpleBlockingQueue(Integer queueSize) {
        this.queueSize = queueSize;
        this.mainList = new LinkedList<>();
        this.mainLock = new ReentrantLock();
        this.produceCondition = this.mainLock.newCondition();
        this.consumeCondition = this.mainLock.newCondition();
    }

    public void addByBlock(T t) throws InterruptedException {
        if (Objects.isNull(t)) {
            throw new NullPointerException("参数t不能为空!");
        }

        mainLock.lock();

        try {
            // 队列已经满了,添加元素等待
            while (Objects.equals(this.count, queueSize)) {
                // 生产等待队列中的线程先等待
                this.produceCondition.await();
            }

            //  队列未满,入队
            this.mainList.addLast(t);
            ++this.count;
            // 消费等待队列中的线程唤醒
            this.consumeCondition.signal();
        } finally {
            mainLock.unlock();
        }
    }

    public T getByBlock() throws InterruptedException {
        mainLock.lock();
        T t = null;
        try {
            // 队列已经满了,添加元素等待
            while (this.count == 0) {
                // 生产等待队列中的线程先等待
                this.consumeCondition.await();
            }

            //  队列未空,出队
            t = this.mainList.pollFirst();
            --this.count;
            // 消费等待队列中的线程唤醒
            this.produceCondition.signal();
        } finally {
            mainLock.unlock();
        }

        return t;
    }
}

参考

< JDK 1.8.0_65 源码>

posted @ 2023-05-17 21:43  sunpeiyu  阅读(23)  评论(0编辑  收藏  举报