本篇内容主要讲解“通过Java源码解析阻塞队列ArrayBlockingQueue”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“通过Java源码解析阻塞队列ArrayBlockingQueue”吧!
公司专注于为企业提供网站建设、成都网站建设、微信公众号开发、商城系统网站开发,微信小程序,软件按需求定制网站等一站式互联网企业服务。凭借多年丰富的经验,我们会仔细了解各客户的需求而做出多方面的分析、设计、整合,为客户设计出具风格及创意性的商业解决方案,创新互联更提供一系列网站制作和网站推广的服务。
Java的阻塞队列,在实现时,使用到了lock和condition,下面是对其主要方法的介绍。
首先看一下,阻塞队列中使用到的锁。
/** Main lock guarding all access **/ final ReentrantLock lock; /** Condition for waiting takes **/ private final Condition notEmpty; /** Condition for waiting puts **/ private final Condition notFull;
主要的锁是一个可重入锁,根据注释,它是用来保证所有访问的同步。此外,还有2个condition,notEmpty用于take等待,notFull用于put等待。
两个condition的初始化方法如下:
public ArrayBlockingQueue(int capacity, boolean fair) { if (capacity <= 0) throw new IllegalArgumentException(); this.items = new Object[capacity]; lock = new ReentrantLock(fair); notEmpty = lock.newCondition(); notFull = lock.newCondition(); }
下面介绍一下put方法。代码如下。
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(); } }
进行put时,首先对待插入的元素进行了非null判断。然后获取锁。之后用一个循环进行判断,如果元素已满,那么,就调用notFull的await方法,进行阻塞。当有别的线程(其实是take元素的线程)调用notFull的siginal方法后,put线程会被唤醒。唤醒后再确认一下count是否小于items.length,如果是,则进行加入队列的操作。
下面介绍一下take方法,代码如下:
public E take() throws InterruptedException { final ReentrantLock lock = this.lock; lock.lockInterruptibly(); try { while (count == 0) notEmpty.await(); return dequeue(); } finally { lock.unlock(); } }
进行take时,同样先要获取锁,然后判断元素个数是否为0,为0时需要等待在notEmpty条件上,等待被唤醒。唤醒之后,会再进行一次元素个数判断,然后进行出队列操作。
分析代码到这里的时候,我产生了一个疑问,如果当前队列慢了,执行put的线程在获取到锁之后,等待notFull条件上。那么,当执行take操作的线程想获取锁时,阻塞队列的锁已经被前面put的线程获取了,那么take将永远得不到机会执行。怎么回事呢?
后来,我查了condition的await方法,它的注释如下:
Causes the current thread to wait until it is signalled or interrupted.
The lock associated with this Condition is atomically released and the current thread becomes disabled for thread scheduling purposes and lies dormant until one of four things happens......
原因在await方法的作用上。因为condition是通过lock创建的,而调用condition的await方法时,会自动释放和condition关联的锁。所以说,当put线程被阻塞后,它实际已经释放了锁了。所以,当有take线程想执行时,它是可以获取到锁的。
另一个问题:当等待在condition上的线程被唤醒时,因为之前调用await前,已经获取了锁,那么被唤醒时,它是自动就拥有了锁,还是需要重新获取呢?
在await方法的注释中,有如下的一段话:
In all cases, before this method can return the current thread must re-acquire the lock associated with this condition. When the thread returns it is guaranteed to hold this lock.
说明当等待在condition上的线程被唤醒时,它需要重新获取condition关联的锁,获取到之后,await方法才会返回。
到此,相信大家对“通过Java源码解析阻塞队列ArrayBlockingQueue”有了更深的了解,不妨来实际操作一番吧!这里是创新互联网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
售后响应及时
7×24小时客服热线数据备份
更安全、更高效、更稳定价格公道精准
项目经理精准报价不弄虚作假合作无风险
重合同讲信誉,无效全额退款