BlockingQueue之ArrayBlockingQueue

BlockQueue

阻塞队列,基于ReentrantLock设计而来的。

能够保证在单个JVM下,无论并发有多大,都能保证都某一时刻,只有一个线程来进行添加和获取操作。

适用于生产者和消费者模型。

下面以BlockingQueue为列子来进行讲解:

/**
 *
 * 经典的生产者和消费者案例!
 * @author liguang
 * @date 2022/7/28 10:53
 */
public class TestOne {

    private static final  int count = 8;

    private static final BlockingQueue<Integer> blockQueue =  new ArrayBlockingQueue(8);

    static class Provider extends Thread{
        @Override
        public void run() {
            while (true){
                try {
                    Thread.sleep(1000);
                    int i = (int) (Math.random() * 100);
                    System.out.println(String.format("当前生产者线程%s,生产的值是:%s",Thread.currentThread().getName(),i));
                    blockQueue.put(i);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    static class Consumer extends Thread{
        @Override
        public void run() {
            while (true){
                try {
                    Thread.sleep(1000);
                    Integer take = blockQueue.take();
                    System.out.println(String.format("当前消费者线程%s,消费的值是:%s",Thread.currentThread().getName(),take));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }



    public static void main(String[] args) {
        // demo1();
        for (int i = 0; i < 10; i++) {
            new Consumer().start();
        }

        for (int i = 0; i < 10; i++) {
            new Provider().start();
        }

        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private static void demo1() {
        Provider provider = new Provider();
        Consumer consumer = new Consumer();
        provider.start();
        consumer.start();
        try {
            provider.join();
            consumer.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

看下构造方法:

    public ArrayBlockingQueue(int capacity, boolean fair) {
        if (capacity <= 0)
            throw new IllegalArgumentException();
        this.items = new Object[capacity];
        // 创建的是锁对象。lock做为成员属性
        lock = new ReentrantLock(fair);
        // 基于锁对象创建两个条件队列
        notEmpty = lock.newCondition();
        notFull =  lock.newCondition();
    }

看下其中的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();
    }
}

重点就是这里的await方法。

        public final void await() throws InterruptedException {
            if (Thread.interrupted())
                throw new InterruptedException();
            // 在条件队列中添加一个等待者。这里是一个单链表结构
            Node node = addConditionWaiter();
            // 然后释放进行锁,等待通知唤醒
            int savedState = fullyRelease(node);
            int interruptMode = 0;
            while (!isOnSyncQueue(node)) {
                LockSupport.park(this);
                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                    break;
            }
            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
                interruptMode = REINTERRUPT;
            if (node.nextWaiter != null) // clean up if cancelled
                unlinkCancelledWaiters();
            if (interruptMode != 0)
                reportInterruptAfterWait(interruptMode);
        }

条件队列:生产者和消费者都待在这一队列里面,单链表结构。

那么这里考虑一种极端情况,如果消费者消费完了,里面没有线程了。那么消费者会通知生产者,让生产者去进行生产:

也就是在await方法中进行操作的。考虑到条件队列中如果有生产者和消费者,那么这种情况下应该如何来进行处理呢?

对应着下面这种情况:

如果说,此时此刻,生产者已经将阻塞队列填满了,那么将会通知条件队列中的线程。而条件队列中的线程会进入到

阻塞队列中,但是发现阻塞队列中还有生产者,那么这个时候需要找到消费者为止。

也就是说,这个时候需要将阻塞队列中的生产者调整到条件队列中,挑选出来对应的消费者。

这个是总体流程结构。

posted @ 2022-07-28 17:22  雩娄的木子  阅读(43)  评论(0编辑  收藏  举报