如何分析阻塞队列ArrayBlockingQueue源码

如何分析阻塞队列ArrayBlockingQueue源码,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。

创新互联专业为企业提供成安网站建设、成安做网站、成安网站设计、成安网站制作等企业网站建设、网页设计与制作、成安企业网站模板建站服务,10多年成安做网站经验,不只是建网站,更提供有价值的思路和整体网络服务。

ArrayBlockingQueue总结

先直接总结ArrayBlockingQueue相关的特性再根据源码来进行说明,它的主要特性如下:

1、他是一个由数组实现的FIFO有界阻塞队列,数组由final修饰

2、ArrayBlockingQueue有界且固定,在构造函数时必须指定大小,确认后不支持改变(确定数组且不可变)

3、在多线程环境下不保证“公平性”;

4、通过ReentrantLock与Condition实现线程安全;

重要属性介绍

主要属性如下图:

 如何分析阻塞队列ArrayBlockingQueue源码

ArrayBlockingQueue的属性还是比较简单,首先是存放数据的Object数组,它是final修饰的,所以队列的长度不可变。

然后三个int属性分别表示下次获取数据时应该从数组的哪里获取,下次保存数据时应该保存到数组的哪里,count记录着还有多少个可以拿。

所有方法首先都必须获取到lock的锁,lock有公平与非公平锁,默认实现的是非公平锁,也可以在初始化ArrayBlockingQueue指定,所以默认ArrayBlockingQueue并不保证公平性。

notEmpty与notFull都是通过lock创建,都是在初始化ArrayBlockingQueue是初始化出来。 

这里简单介绍了属性的作用,接下来会通过源码再来理解它的作用。

最关键的两个私有方法

首先要说两个私有方法,应该队列主要的方法最后都依赖这两个私有方法,直接看源码如下图:

 如何分析阻塞队列ArrayBlockingQueue源码

enqueue方法用来把数据保存到数组items中,会递增putIndex,也就是下次应该保存的位置,如果putIndex等于了数组的长度,则下次为0。

最后会唤醒那些调用notEmpty.await()阻塞的线程,实际上只有take方法调用了。 

dequeue方法是获取数据,获取的是takeIndex处的数据,在获取过后会把items[takeIndex]处设置为null,同样递增takeIndex后如果等于了数组的长度则会被置为0。

最后会唤醒那些调用notFull.await()阻塞的线程,只有put方法调用了。 

所以主要的变化在于putIndex和takeIndex,这里总结了他们有如下4种关系:

 如何分析阻塞队列ArrayBlockingQueue源码

如果不加保护他们不止这些关系,比如takeIndex比putIndex跑的快,那么就会获取到null值,获取putIndex比takeIndex多走一个轮回还多那么就会出现数据被覆盖,造成数据丢失。

只有保证它们是这几种关系才能保证数据的安全性,避免数据被覆盖或者获取到null值,并且实现了FIFO先进先出,而队列提供的公共方法都必须要保证这种安全

添加数据方法介绍

ArrayBlockingQueue提供了4个添加方法add、offer、offer(指定阻塞时间)、put;

add方法调用的是offer方法,而offer方法先获取到锁,再判断队列是否已满,已满直接返回false,没有满则调用enqueue保存数据。所以add与offer没有阻塞。

offer还有一个可以在队列已满情况下阻塞指定时间(timeout)在尝试保存的方法,在判断队列已满的情况会调用”nanos = notFull.awaitNanos(nanos);”阻塞线程,一定时间后如果还是满的则会返回false。 

put获取到锁,如果数组已满则调用notFull.await一直阻塞等待唤醒,唤醒后再次验证是否已满,没满则调用enqueue,否则再次阻塞。所以向队列中加数据只有put方法才支持真正的阻塞,保证添加成功,其他方法会可能保存失败

获取数据方法介绍

获取数据提供了poll、poll(指定阻塞时间)、take、peek

poll方法先获取到锁,如果count==0则返回null,否则调用dequeue方法获取结果。

poll(指定阻塞时间)在判断count==0时会先阻塞执行时间,然后再次判断,如果还是等于0则返回null,如果不等于0则调用dequeue方法获取结果。 

take方法先获取到锁然后在循环判断count是否等于0如果等于0则调用notEmpty.await()阻塞,否则调用dequeue获取结果,同样take方法也会保证一定能拿到数据,否则会一直阻塞。 

peek是偷看的意思,peek方法在获取到锁后直接获取item[takeIndex]的元素返回,然后不做任何事情,就好像偷偷看下下一次会获取哪一个元素,但是不影响队列。

看完上述内容,你们掌握如何分析阻塞队列ArrayBlockingQueue源码的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注创新互联行业资讯频道,感谢各位的阅读!


分享题目:如何分析阻塞队列ArrayBlockingQueue源码
网址分享:http://myzitong.com/article/jhjdpi.html