当前位置: 首页 > 后端技术 > Java

你亲手写过阻塞队列吗?

时间:2023-04-01 21:34:27 Java

面试官:你好,可以先自我介绍一下有人:面试官你好,我叫张口,面试全是吹牛,某年毕业,国内大学毕业,从事某某工作项目。.....面试官微微一笑,抚摸着他稀疏的头发:看你的简历,你是不是精通多线程?那你手写过阻塞队列吗?某人心里有一万个问号,到底是什么堵着队?平时基本都是crud,顶多用多线程跑数据。某人:我从来没有手写过。面试官:哦,说说堵车吧。有人犹豫了:这个我忘了。面试官:没关系,我们下一步。这里省略一万字。面试官扭动重负的颈椎:你先过来,你回去等通知。某人:好的。不出所料,有人等了一个月,苦苦等待,还是没有接到预想中的电话。1.什么是队列?队列是一种特殊的线性表。它的特殊之处在于只允许在表的前端(front)进行删除操作,在表的后端(rear)进行插入操作。和栈一样,队列是一个操作受限的线性表。插入操作结束的称为队尾,删除操作结束的称为队头。排队其实和平时排队一样。顺序是先排队的先买东西,后排队的最后买东西。队列中的第一个称为队头,最后一个称为队尾。这是先进先出队列,这是与栈最大的区别。2.什么是阻塞队列?当队列为空时,消费者挂掉,当队列满时,生产者挂掉。这就是生产消费者模型。阻塞其实就是挂起线程。由于生产者的生产速度和消费者的消费速度不匹配,可以通过阻塞队列的方式暂时阻塞快队列。比如生产者每秒生产2条数据,消费者每秒消费一条数据。当队列满时,生产者会阻塞(挂起),等待消费者消费,然后醒来。阻塞队列会通过挂起来实现生产者和消费者之间的平衡,这是与普通队列最大的区别。3、阻塞队列如何实现?其实jdk已经给我们提供了一个实现方案。Java5添加了并发包。concurrent包中的BlockingQueue是一个阻塞队列。我们不需要关心BlockingQueue是如何实现阻塞的。一切都为我们打包。我们只需要做一个没有感情的API调用者就可以了。4.如何使用BlockingQueue?BlockingQueue本身只是一个接口,它指定了阻塞队列的方法,主要由几个实现类来实现。4.1BlockingQueue主要方法1.插入数据(1)offer(Ee):如果队列未满,返回true,如果队列满,返回false(未阻塞)(2)offer(Ee,longtimeout,TimeUnitunit):可以设置等待时间,如果队列已满则等待。如果超过等待时间,则返回false(3)put(Ee):没有返回值,等待队列为空2.获取数据(1)poll():如果有数据,则出队列,ifthereisnodata,Returnnull(2)poll(longtimeout,TimeUnitunit):可以设置等待时间,如果没有数据则等待,如果等待时间超过则returnnull(3)take():如果有数据,则出队列。如果没有数据,则一直等待(阻塞)4.2BlockingQueue主要实现类1.ArrayBlockingQueue:ArrayBlockingQueue是基于数组实现的。它是一个在初始化时通过设置数组长度的有界队列,ArrayBlockingQueue和LinkedBlockingQueue的区别在于ArrayBlockingQueue只有一个锁对象,而LinkedBlockingQueue是两个锁对象。一个锁对象将导致生产者获取锁或消费者获取锁。两者竞争锁,不能并行。2、LinkedBlockingQueue:LinkedBlockingQueue是基于链表实现的。与ArrayBlockingQueue不同的是,大小是可以初始化的。如果未设置,则默认设置大小为Integer.MAX_VALUE。LinkedBlockingQueue有两个可以并行处理的锁对象。3、DelayQueue:DelayQueue是一个基于优先级的无界队列。队列元素必须实现延迟接口并支持延迟获取。元素按时间排序。只有当元素过期时,消费者才能将它们从队列中取出。4.PriorityBlockingQueue:PriorityBlockingQueue是一个基于优先级的无界队列。底层是基于数组存储元素。元素按优先顺序存储。优先级是通过Comparable的compareTo方法(自然排序)实现的,这与其他阻塞队列不同。更重要的是,它只会阻塞消费者,不会阻塞生产者,而且阵列会不断扩大。这是彩蛋,使用时要小心。5.SynchronousQueue:SynchronousQueue是一个特殊的队列,内部没有容器,所以当生产者生产一条数据时,它是阻塞的,生产者必须等待消费者消费完它才能再次生产。称它为队列有点不合适。现实生活中,只有多人才能称为一个团队,一个人称为一个团队,多少有点说不通。5、我手写的阻塞队列是参考ArrayBlockingQueue的源码写的,欢迎指正。/***@authoryz*@version1.0*@date2020/10/3111:24*/publicclassYzBlockingQuery{privateObject[]tab;//队列容器privateinttakeIndex;//出列下标privateintputIndex;//入队下标privateintsize;//元素个数privateReentrantLockreentrantLock=newReentrantLock();privateConditionnotEmpty;//读取条件privateConditionnotFull;//写入条件publicYzBlockingQuery(inttabCount){if(tabCount<=0){newNullPointerException();}tab=newObject[tabCount];notEmpty=reentrantLock.newCondition();notFull=reentrantLock.newCondition();}publicbooleanoffer(Objectobj){if(obj==null){thrownewNullPointerException();}try{//获取锁reentrantLock.lock();//队列已满while(size==tab.length){System.out.println("队列已满");//阻止notFull.await();}tab[putIndex]=obj;if(++putIndex==tab.length){putIndex=0;}大小++;//唤醒读线程notEmpty.signal();返回真;}catch(Exceptione){//唤醒读线程notEmpty.signal();}最后{reentrantLock.unlock();}返回假;}publicObjecttake(){try{reentrantLock.lock();while(size==0){System.out.println("队列为空");//阻塞notEmpty.await();}对象obj=tab[takeIndex];//如果到达最后一个,则从头开始if(++takeIndex==tab.length){takeIndex=0;}尺寸-;//唤醒写线程notFull.signal();返回对象;}catch(Exceptione){//唤醒写线程notFull.signal();}最后{reentrantLock.unlock();}返回空值;}发布icstaticvoidmain(String[]args){Randomrandom=newRandom(100);YzBlockingQueryyzBlockingQuery=newYzBlockingQuery(5);线程thread1=newThread(()->{for(inti=0;i<100;i++){try{Thread.sleep(300);}catch(InterruptedExceptione){e.printStackTrace();}yzBlockingQuery。offer(i);System.out.println("生产者生产了:"+i);}});Threadthread2=newThread(()->{for(inti=0;i<100;i++){try{Thread.sleep(1000);}catch(InterruptedExceptione){e.printStackTrace();}对象取=yzBlockingQuery.take();System.out.println("消费者消费了:"+take);}});thread1.start();thread2.start();}}来源:https://blog.csdn.net/qq_3830...