源码解读:堵塞式队列LinkedBlockQueue
一个基于链表构建的FIFO(fisrt in first out)阻塞式队列。
简介
类图
LinkedBlockingQueue是一个线程安全的阻塞队列,实现了先进先出等特性,是作为生产者消费者的首选,可以指定容量,也可以不指定,不指定的话默认最大是Integer.MAX_VALUE,其中主要用到put和take方法,put方法将一个对象放到队列尾部,在队列满的时候会阻塞直到有队列成员被消费,take方法从head取一个对象,在队列为空的时候会阻塞,直到有队列成员被放进来。
transient关键字
- (1)一旦变量被transient修饰,变量将不再是对象持久化的一部分,该变量内容在序列化后无法被访问。
- (2)transient关键字只能修饰变量,而不能修饰方法和类。注意,本地变量是不能被transient关键字修饰的。变量如果是用户自定义类变量,则该类需要实现Serializable接口。
- (3)一个静态变量不管是否被transient修饰,均不能被序列化(如果反序列化后类中static变量还有值,则值为当前JVM中对应static变量的值)。序列化保存的是对象状态,静态变量保存的是类状态,因此序列化并不保存静态变量。
使用场景
- (1)类中的字段值可以根据其它字段推导出来,如一个长方形类有三个属性长度、宽度、面积,面积不需要序列化。
- (2) 一些安全性的信息,一般情况下是不能离开JVM的。
- (3)如果类中使用了Logger实例,那么Logger实例也是不需要序列化的
成员变量
字段类型 | 字段名 | 备注 |
---|---|---|
static class Node |
元素封装类 | |
int | capacity | 容器容量,默认为int的最大值 |
AtomicInteger | count | 当前容器中的元素数量 |
Node |
head,last | 链表的开头与结尾元素 |
ReentrantLock | takeLock,putLock | 取锁与放锁 |
Condition | notEmpty,notFull | putLock/takeLock.newCondition() |
构造方法
构建一个容量为int最大值的链表,可以发现容量只是赋给了capacity
变量,并没有如ArratList
那样生成一个连续的长度为容量值的字的内存空间。
1 | public LinkedBlockingQueue() { |
public void put(E e) throws InterruptedException {
素添加方法,在队列满后调用该方法的线程会被阻塞,直到有空余空间。
1 | public void put(E e) throws InterruptedException { |
与put犯法类似,在指定时间内仍未放入队列则报异常,实现关键是由notFull信号在指定时间内未获取到notify信号实现的。
1 | public boolean offer(E e, long timeout, TimeUnit unit) |
public boolean offer(E e)
在队列末尾立即添加目标元素,与put方法相比,该方法不会导致调用线程阻塞。
public E take() throws InterruptedException
与put方法相对应,这是一个获取队头元素的线程安全方法,若队列中没有元素则会导致调用线程阻塞。
public E poll()
获取队头元素并删除,与put方法相比,该方法不会在没有元素时阻塞,而是直接返回null
public E peek()
获取但不删除队头元素
public int drainTo(Collection<? super E> c)
将列表中的元素放入到给定集合中,并从自身队列中删除这些元素。与for循环poll相比,该方法更为高效,并且不会在轮训过程中释放取锁。