当前位置: 首页 > 科技观察

面试官:你知道阻塞队列吗?

时间:2023-03-22 10:42:03 科技观察

前言本节讨论什么是阻塞队列,一起来看看吧!什么是阻塞队列先说说为什么要引入阻塞队列。我们知道服务器的资源是有限的,就拿典型的生产者和消费者模型来说吧。如果consumer没有什么东西可以消费了,但是它还在执行,这无疑是一种系统资源的浪费,所以我们需要阻塞consumer,对它也是如此。生产者没有什么可生产的,或者没有地方储存它生产的东西。这时候我们就需要对producer进行block。但是在开发中,这种模型往往运行在多线程环境下,需要共享资源来获得更高的性能,但是这样也会造成线程安全问题,比如死锁、重复消费等,所以阻塞队列就是为了帮助我们解决它。这些问题。BlockingQueue让我们看看Java为我们提供的有用工具。首先介绍一下BlockingQueue。这一节,我们主要讲一下它的用法。BlockingQueue是Javautil.concurrent包下的一个类。BlockingQueue提供了一种“线程安全的队列访问方式”。并发契约下很多高级同步类的实现都是基于BlockingQueue。BlockingQueue一般用于生产者消费者模式。生产者是向队列中添加元素的线程,消费者是从队列中取出元素的线程。“BlockingQueue是一个用于存储元素的容器。”publicinterfaceBlockingQueueextendsQueue{....}本身就是一个接口,我们来看看它常用的实现类。ArrayBlockingQueue是由数组实现的有界阻塞队列。该队列按照先进先出(FIFO)的原则对元素进行排序,支持公平锁和非公平锁。add()添加一个元素。//初始容量为3BlockingQueuequeue=newArrayBlockingQueue<>(3);System.out.println(queue.add("1"));System.out.println(queue.add("2"));System.out.println(queue.add("3"));System.out.println(queue.add("4"));我们发现添加到4时,报错Exceptioninthread"main"java.lang.IllegalStateException:Queuefull。remove()删除一个元素,如果为空则返回异常。//初始容量为3BlockingQueuequeue=newArrayBlockingQueue<>(3);System.out.println(queue.add("1"));System.out.println(queue.add("2"));System.out.println(queue.add("3"));//System.out.println(queue.add("4"));System.out.println(queue.remove());System.out.println(队列);打印:truetruetrue1[2,3]从结果来看,符合FIFO规则。如果我想删除指定的元素怎么办?很简单,使用remove("3")。offer()和add方法类似,但是不会报错,会返回false,offer(e,time,unit)支持超时。BlockingQueuequeue=newArrayBlockingQueue<>(3);System.out.println(queue.offer("1"));System.out.println(queue.offer("2"));System.out.println(queue.offer("3"));System.out.println(queue.offer("4"));truetruetruefalsepoll()类似于remove,但是不是返回异常,而是返回null,poll(time,单元)。BlockingQueuequeue=newArrayBlockingQueue<>(3);System.out.println(queue.poll());nulltake()类似于poll,但是会造成线程阻塞。publicstaticvoidmain(String[]args)throwsInterruptedException{BlockingQueuequeue=newArrayBlockingQueue<>(3);System.out.println(queue.take());}运行后发现程序被阻塞了。put()添加元素,当容器满了会造成线程阻塞。publicstaticvoidmain(String[]args)throwsInterruptedException{BlockingQueuequeue=newArrayBlockingQueue<>(1);queue.put("1");queue.put("2");}运行后发现,执行到2的时候就卡住了。以上是它的常用方法,其他的实现类就不一一给大家演示了。方法大同小异,都是基于BlockingQueue接口。您可以尝试自己运行它。LinkedBlockingQueue是一个由链表结构组成的有界队列,这个队列的长度是Integer.MAX_VALUE。SynchronousQueue是一个不存储元素的阻塞队列。每个put操作都必须等待一个take操作,否则不能添加元素。支持公平锁和非公平锁。SynchronousQueue的一种使用场景是在线程池中。Executors.newCachedThreadPool()使用的是SynchronousQueue,上一节讲线程复用的时候遇到过。LinkedTransferQueue是由链表结构组成的无界阻塞队列,与其他队列等价。LinkedTransferQueue有更多的transfer和tryTransfer方法。PriorityBlockingQueue是一个无界队列,支持线程优先级排序。默认按自然顺序排序。您还可以自定义compareTo()方法来指定元素排序规则。无法保证具有相同优先级的元素的顺序。DelayQueue是一个无界队列,实现了PriorityBlockingQueue实现延迟获取。创建元素时,可以指定从队列中获取当前元素所需的时间。只有在延迟期满后才能从队列中获取元素,这在缓存设计和定时任务调度中经常会遇到。结束语本节主要介绍常用的阻塞队列及其基本使用。