Java并发包中的并发队列简记
ConcurrentLinkedQueue
ConcurrentLinkedQueue内部的队列使用带头节点的单向链表实现,并且维持头尾两个指针,头指针出队、尾指针入队。该队列的出队入队操作都是线程安全的。
保证安全的方式
对于头尾指针均使用volatile关键字修饰从而保证可见性,对于头尾指针的修改使用CAS操作保证了原子性。所以对于出入队是线程安全的。
主要方法
offer:入队操作
add:添加元素,内部通过调用offer实现
poll:出队操作,删除队头元素并返回
peek:获取对头元素,不删除结点
size:返回队列的大小,由于队列没有加锁,返回结果可能不准确,在返回时队列有可能被其它线程修改
remove:删除队列中指定的元素,有多个满足的元素时删除第一个
contains:判断是否包含某个元素,和size一样的原因,导致结果也可能不准确
LinkedBlockingQueue
LinkedBlockingQueue同样使用单向链表,并且维持头尾两个指针,另外使用了一个原子变量count来记录当前队列的结点数量。
保证线程安全的方式
对于出队和入队分别设置了takeLock和putLock两个独占锁,保证同一时刻只有一个线程可以进行出队或者入队操作,另外使用notEmpty和notFull两个条件变量用于存由于放入队和出队阻塞的线程。
主要方法
offer:非阻塞的入队操作,如果没有空间,则直接丢弃入队的元素返回false
put:阻塞的入队操作,如果没有空间,就把当前线程放入notFull的条件队列中,并且在获取锁时可相应中断
poll:非阻塞的出队操作,如果队列为空则直接返回false
peek:获取对头元素,不删除队头,该操作也是非阻塞的
take:阻塞的出队操作,如果队列为空,则线程被放入notEmpty条件队列中,并且在获取锁时可相应中断
remove:删除队列指定的元素
size:获取队列的大小,通过count原子变量获取,由于出对入队均加锁,所以结果是准确的
ArrayBlockingQueue
ArrayBlockingQueue与LinkedBlockingQueue的具体操作基本一致,不同点在于ArrayBlockingQueue底层是使用数组实现的循环队列,另外关于加锁方面ArrayBlockingQueue对出队和入队使用的是同一个锁,锁的粒度比LinkedBlockingQueue大,在获取size时ArrayBlockingQueue需要加锁获取,因为count使用的是普通变量。