阻塞队列

阻塞队列有两种阻塞

队列是空的,拿的时候拿不到,阻塞了
队列是满的,放的时候放不进,阻塞了

阻塞队列在JDK里面有一个专门的接口BlockingQueue
在这里插入图片描述
并不是所有的方法都是阻塞的方法
插入元素和拿取元素成对出现的两种操作

非阻塞类的方法
add()插入元素,往满的队列插入时元素时插不进会抛出异常
remove()拿取元素,从空的队列拿元素时拿不出来会抛出异常

非阻塞类的方法
offer()插入元素,往满的队列插入时元素时插不进会返回false
poll()拿取元素,从空的队列拿元素时拿不出来会返回null

阻塞类的方法
put()插入元素,往满的队列插入时元素时插不进线程会被阻塞
take()拿取元素,从空的队列拿元素时拿不出来线程会被阻塞

生产者消费者模式

生产者生产数据,消费者消费数据
如果生产者生产的很快,消费者消费速度慢,那么生产者要等消费者消费完再继续生产
如果是消费者的速度快,大部分时间消费者是在等生产者
为了平衡生产者和消费者之间能力不均衡的情况,在生产者和消费者之间放一个容器,生产者生产后放入容器,只管放入,消费者从容器拿数据,不关心数据从哪里来,平衡了生产者和消费者性能不均衡的问题,生产者和消费者结耦

阻塞队列用在生产者消费者问题中好处:

  1. 生产者消费者分离结耦
  2. 平衡生产者消费者之间性能不均衡问题

常用阻塞队列

ArrayBlockingQueue:一个由数组结构组成的有界阻塞队列。
LinkedBlockingQueue:一个由链表结构组成的有界阻塞队列。
PriorityBlockingQueue:一个支持优先级排序的无界阻塞队列。
DelayQueue:一个使用优先级队列实现的无界阻塞队列。
SynchronousQueue:一个不存储元素的阻塞队列。
LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。
LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列。

有界与无界:
有界:队列长度是有限的,满了以后生产者就会被阻塞
无界:可以不听的放东西,不会被阻塞

比如ArrayBlockingQueue的构造函数必须传入一个容量,要指明当前ArrayBlockingQueue容量是多大
在这里插入图片描述

public ArrayBlockingQueue(int capacity) {
        this(capacity, false);
    }

查看无界的支持优先级的阻塞队列PriorityBlockingQueue

发现也有支持传入int,但这里是初始化容量大小,没有限定最大大小
在这里插入图片描述

public PriorityBlockingQueue(int initialCapacity) {
        this(initialCapacity, null);
    }

在一般的队列中是根据放入元素的前后顺序进行排队的,支持优先级的含义是在放入元素时可以先比较下,放入时根据某种方式进行比较,比较结果谁大或者谁小就放到队列前头,允许放入元素进行排序,默认是按照自然排序的。允许传入比较器

public PriorityBlockingQueue(int initialCapacity,
                                 Comparator<? super E> comparator) {
        if (initialCapacity < 1)
            throw new IllegalArgumentException();
        this.lock = new ReentrantLock();
        this.notEmpty = lock.newCondition();
        this.comparator = comparator;
        this.queue = new Object[initialCapacity];
    }

综上:有界规定了最大容量,无界没有规定最大容量
当然,在实际的开发过程中,没法做到真正的无界,因为资源总是有限的,尽量使用有界控制容量大小
无界队列拿取还是会阻塞的

DelayQueue:一个使用优先级队列实现的无界阻塞队列
支持元素的延时获取

public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
    implements BlockingQueue<E> {
    ......
}

DelayQueue除了是个泛型还有个约束,要实现Delayed这个接口

public interface Delayed extends Comparable<Delayed> {

    /**
     * Returns the remaining delay associated with this object, in the
     * given time unit.
     *
     * @param unit the time unit
     * @return the remaining delay; zero or negative values indicate
     * that the delay has already elapsed
     */
    long getDelay(TimeUnit unit);
}

getDelay是返回当前元素剩余时长
谁的剩余时间短谁就排在前头,先被取出来
阻塞多了一种约束:及时有元素,元素的剩余时间没有到,也拿不出来
用处:单机缓存系统,时间设置过期

SynchronousQueue:一个不存储元素的阻塞队列
内部没有任何容器,当我们使用生产者线程使用一个put操作往SynchronousQueue阻塞队列里面放东西的时候,队端必须有一个消费者使用take方法把这个元素拿走,否则生产者不能继续添加元素的,数据的直接传递
生产者直接给消费者的话就产生耦合了,生产者就必须要知道消费者是谁了,使用SynchronousQueue后生产者往队列里面放,不用关系消费者有几个消费者是谁。

LinkedTransferQueue:一个由链表结构组成的无界阻塞队列
多了一个尝试传输
生产者往队列里面放元素时,发现正好有消费者在等待拿元素,它就直接把元素交给消费者,不再往队列里面放了

public void transfer(E e) throws InterruptedException {
        if (xfer(e, true, SYNC, 0) != null) {
            Thread.interrupted(); // failure possible only due to interrupt
            throw new InterruptedException();
        }
    }

还有tryTransfer,会试探下有没有消费者拿,如果不试探直接给,没有消费者接受的话,transfer方法会一直阻塞在这个位置,必须等有消费者拿走才能返回
tryTransfer会尝试下有没有消费者,没有消费者消费就放入队列里面

public boolean tryTransfer(E e) {
        return xfer(e, true, NOW, 0) == null;
    }

LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列
一般的队列一个入口一个出口,双向同时作为出口和入口 (减少一个竞争),Deque双端
它的方法会多,firt,last,从头从尾取(放)
在这里插入图片描述

以下三个平常可能用的多一些:
ArrayBlockingQueue:一个由数组结构组成的有界阻塞队列。
LinkedBlockingQueue:一个由链表结构组成的有界阻塞队列。
DelayQueue:一个使用优先级队列实现的无界阻塞队列。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值