您好,登录后才能下订单哦!
如何分析阻塞队列ArrayBlockingQueue源码,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。
先直接总结ArrayBlockingQueue相关的特性再根据源码来进行说明,它的主要特性如下:
1、他是一个由数组实现的FIFO有界阻塞队列,数组由final修饰;
2、ArrayBlockingQueue有界且固定,在构造函数时必须指定大小,确认后不支持改变(确定数组且不可变);
3、在多线程环境下不保证“公平性”;
4、通过ReentrantLock与Condition实现线程安全;
主要属性如下图:
ArrayBlockingQueue的属性还是比较简单,首先是存放数据的Object数组,它是final修饰的,所以队列的长度不可变。
然后三个int属性分别表示下次获取数据时应该从数组的哪里获取,下次保存数据时应该保存到数组的哪里,count记录着还有多少个可以拿。
所有方法首先都必须获取到lock的锁,lock有公平与非公平锁,默认实现的是非公平锁,也可以在初始化ArrayBlockingQueue指定,所以默认ArrayBlockingQueue并不保证公平性。
notEmpty与notFull都是通过lock创建,都是在初始化ArrayBlockingQueue是初始化出来。
这里简单介绍了属性的作用,接下来会通过源码再来理解它的作用。
首先要说两个私有方法,应该队列主要的方法最后都依赖这两个私有方法,直接看源码如下图:
enqueue方法用来把数据保存到数组items中,会递增putIndex,也就是下次应该保存的位置,如果putIndex等于了数组的长度,则下次为0。
最后会唤醒那些调用notEmpty.await()阻塞的线程,实际上只有take方法调用了。
dequeue方法是获取数据,获取的是takeIndex处的数据,在获取过后会把items[takeIndex]处设置为null,同样递增takeIndex后如果等于了数组的长度则会被置为0。
最后会唤醒那些调用notFull.await()阻塞的线程,只有put方法调用了。
所以主要的变化在于putIndex和takeIndex,这里总结了他们有如下4种关系:
如果不加保护他们不止这些关系,比如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源码的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注亿速云行业资讯频道,感谢各位的阅读!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。