阻塞队列及方法介绍

1.BlockingQueue简介

阻塞队列实际上就是个队列,只不过当队列里面东西是空的时候,当从队列中拿数据的时候会阻塞,当队列满了的时候,向队列中添加元素也会阻塞。当我不断取元素直到队列里的元素为空,会自动挂起线程,当我队列里面突然有元素了,会自动唤醒取元素的线程。这个阻塞队列的好处是我们不需要关心什么时候需要阻塞线程,什么时候需要唤醒线程,因为这一切BlockingQueue都一手给我包办了。

2.常见的BlockingQueue

2.1ArrayBlockingQueue

基于数组的阻塞队列实现,在其内部维护了一个定长的数组,以便存储缓存的对象,同时它里面还维护了两个整型变量,分别标识着队列的头部和尾部在数组中的位置。它在生产者放入数据和消费者获取数据,都是同时共用一个锁对象,由此意味着两者无法真正的并行。

2.2LinkedBlockingQueue

基于链表的阻塞队列,内部也维持了一个数据缓冲队列(该队列有一个链表组成),与ArrayBlockingQueue不同的是这个的最大容量是Integer.MAX_VALUE。而且他对于生产者和消费者端分别采用了独立的锁来控制同步,这意味着在高并发情况下生产者和消费者可以并行地操作队列中的数据。

2.3 DelayQueue

DelayQueue中的元素只有当其指定的延迟时间到了,才能够从队列中获取到元素,他没有大小限制因此生产者永远不会阻塞。而且使用优先级队列实现延迟。

2.4PriorityBlockingQueue

他是一个支持优先级排序的无界阻塞序列,他也不会阻塞生产者,只会阻塞消费者,但是生产者生产的速度绝对不会快于消费者消费的速度,否则时间一长,会最终耗尽所有可用的堆空间。

2.5SynchronousQueue

一种无缓冲的等待队列,类似于无中介的直接交易,生产者生产好了之后必须得等消费者消费,如果没有消费者消费他就会一直等待,对于消费者来说也是这样。

2.6LinkedTransferQueue

LinkedTransferQueue是一个由链表构成的无界阻塞TransferQueue队列。相对于其他阻塞队列,LinkedTransferQueue多了tryTransfer和transfer方法。LinkedTransferQueue采用一种预占模式。

  • 队列不为空,直接取走数据
  • 队列为空,那就生成一个节点元素为null的入队,然后消费者线程在这等待
  • 如果生产者线程发现有一个null节点在队列上,生产者线程就不入队了直接将元素填充到该节点,并唤醒消费者线程取走元素,从调用的方法返回。

2.7LinkedBlockingDeque

LinkedBlockingDeque是一个由链表组成的双向阻塞队列,即可以从队列的两端插入和移除元素。还有一个特点就是可以设置超时时间参数,超时后返回false表示操作失败,也可以不设置超时参数一直阻塞,中断之后抛出InterruptedException异常。读元素时同样可以设置超时参数。

3.阻塞队列核心方法

  • 插入
    1.add(e):当阻塞队列满时,再往队列里add插入元素会抛IllegalStateException:Queue full
    2.offer(e):插入方法,成功true失败返回false
    3.put(e):当阻塞队列满时,生产者线程继续往队列里添加元素,队列会一直阻塞生产者线程知道put数据or响应中断退出。
    4.offer(e,time,unit):当阻塞队列满的时候,队列会阻塞生产者线程一定时间,超过限时后生产者线程会退出。

  • 移除
    1.remove():当队列为空的时候,再往队列里remove移除元素会抛NoSuchElementException
    2.poll():移除方法,成功返回出队列的元素,队列里没有就返回null。
    3.take():当队列为空消费者线程试图从队列里take元素,队列会一直阻塞消费者线程知道队列可用
    4.poll(time,unit):当队列为空的时候,会阻塞一段时间超时后消费者线程退出。

  • 检查
    1.element():当队列为空时直接抛出异常
    2.peek():当队列为空时阻塞

add,remove,offer,poll就不演示了,演示一下后面的

        BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(3);
        blockingQueue.put("a");
        blockingQueue.put("b");
        blockingQueue.put("c");
        blockingQueue.put("d");

结果就是阻塞了
阻塞队列及方法介绍_第1张图片

        BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(3);
        blockingQueue.put("a");
        blockingQueue.put("b");
        blockingQueue.put("c");
        System.out.println(blockingQueue.take());
        System.out.println(blockingQueue.take());
        System.out.println(blockingQueue.take());
        System.out.println(blockingQueue.take());

阻塞队列及方法介绍_第2张图片

        blockingQueue.offer("a");
        blockingQueue.offer("b");
        blockingQueue.offer("c");
        long start = System.currentTimeMillis();
        blockingQueue.offer("w",3l, TimeUnit.SECONDS);
        long end = System.currentTimeMillis();
        System.out.println((end - start));

阻塞队列及方法介绍_第3张图片
可以看出确实阻塞了3s

你可能感兴趣的:(数据结构,java,后端,链表)