线程安全的无界非阻塞队列,其底层数据结构使用单向链表实现,对于出队和入队操作使用CAS来实现线程安全
新元素会被插入队列的末尾
队列头获取元素
添加一个元素
添加一个元素,底层使用offer()
删除一个元素,获取元素
获取队首的参数
移除一个值
不精确的判断
ConcurrentLinkedQueue的底层使用单向链表数据结构来保存队列元素,每个元素被包装成一个Node节点。队列是靠头、尾节点来维护
创建队列头、尾节点指向一个item为null的哨兵节点
第一次执行peek或者first操作时会把head执行第一个真正的队列元素。
阻塞队列
有界
单向链表实现,两个Node用来存放队首尾节点
两个ReentrantLock实例,分别用来控制元素出队和入队,takeLock用来控制同时只有一个线程可以从队列头获取元素,
putLock控制同时只有一个线程可以在队列尾添加元素。
notEmpty和notFull:条件变量,用来存放出队和入队时被阻塞的线程。
向队列尾部插入一个元素,如果队列中有空闲则插入成功后返回true,如果队列满丢弃当前元素返回false-----非阻塞
如果空闲插入成功,如果已满,则阻塞当前进程,直到队列有空闲插入成功------------------阻塞的
从队列头部获取并移除一个元素并返回,如果队列维空,则返回null,--------------------不阻塞
从队列头部元素中返回,不移除,空则返回null---------------不阻塞
获取当前队列头部元素并从队列里面删除它,如果队列为空则阻塞当前线程---------------------阻塞的
删除队列里面指定的元素,有则返回true
获取出锁和入锁
删除元素之后,唤醒notFull条件队列里面的线程,执行put方法
精确的,因为使用的AtomicInteger 存储count
为啥ConcurrentLinkedQueue中的size不精确,因为使用原子变量保证队列个数需要保证入队、出队操作和原子变量操作都是原子性的
LinkedBlockingQueue的内部是通过单向链表实现的,使用头、尾节点来进行入队和出队操作,也就是入队操作都是队尾节点进行操作,出队操作都是队头节点进行操作
对头、为基点的操作分别使用了单独的独占锁从而保证原子性,所以出队和入队是可以同时进行的。另外对头、尾节点的独占锁都配备了一个条件队列,用来存放被阻塞的线程,并结合入队、出队操作实现了一个生产者消费者模型。
有界阻塞队列LinkedBlockingQueue
有界数组队列ArrayBlockingQueue
向队列尾部插入一个元素,如果队列有空闲空间插入成功后返回true,如果队列满,返回false,-----------------------------------------------不阻塞,独占锁
向队尾插入一个元素,空闲则插入后直接返回true,如果队列满了,则阻塞,直到true----------------------------------------阻塞,独占锁
从队列头部获取一个元素,队列为空则返回null----------------------------不阻塞
从队列头部获取一个元素,不移除
非要移除,不移除就阻塞
准确的
ArrayBlockingQueue通过使用全局独占锁实现了一个同时只有一个线程进行入队和出队的操作,这个锁的粒度比较大,优点类是sychronized。其中offer和poll操作通过简单的加锁进行入队、出队操作。而put、take操作则使用条件变量实现的。相比于ArrayBlockingQueue的size操作的结果是精确的。
在队列中插入一个元素,独占锁
获取队列内部堆树的根节点元素
调用offer
获取根节点元素,阻塞的
精确的,加锁的
priorityBlockingQueue队列在内部使用二叉树堆维护元素优先级,使用数组作为元素存储的数据结构,会扩容。
在内部使用一个独占锁来控制同时只有一个线程进行入队和出队。另外使用notEmpty来确保take方法的阻塞线程
队列里面的元素实现Delayed接口,由于每一个元素都有一个过期时间,所以要实现获知当前元素还剩下多少时间过期了的结构,内部使用优先级队列来实现
插入元素到队列
移除队列里面延迟时间过期的元素,没有则z阻塞
获取并移除对头过期元素,没有则返回null
计算队列元素
其内部使用PriorityQueue存放数据,使用ReentrantLock实现线程同步。另外队列里面的元素要实现Delayed接口,其中一个是获取当前元素到过期时间剩余时间的接口,在出队时判断元素是否过期,一个时元素之间的比较接口,因为这是一个优先级队列。
原文:https://www.cnblogs.com/sicheng-li/p/13204953.html