LinkedBlockingQueue

接ArrayBlockingQueue,这里我谈下我对LinkedBlockingQueue的理解。

由阻塞队列的ArrayBlockingQueue和LinkedBlockingQueue,我们很容易联想到List的两种实现:ArrayList和LinkedList。ArrayList与ArrayBlockingQueue相似,底层都使用了数组,同样LinkedList和LinkedBlockingQueue也类似,底层使用了链表。不过这里的链表还是有些许不同的:

1. LinkedList使用了双向链表,而LinkedBlockingQueue使用了单向链表。

2. LinkedList的容量理论上是无限的,而LinkedBlockingQueue却是有限的。

让我们来看看构造函数:

LinkedBlockingQueue_第1张图片
构造函数

无参构造函数实际上创建了一个大小为Integer.MAX_VALUE,而有参构造函数传入的也是int。也就是说其实LinkedBlockingQueue是有界的。

接下来,我们看看它所使用的锁。

LinkedBlockingQueue_第2张图片

从代码中可以看出,它有两个锁,一个takeLock(读锁),一个putLock(写锁)。这与ArrayBlockingQueue是不一样的。ArrayBlockingQueue只有一个锁。为什么有这样的差异呢?ArrayBlockingQueue底层使用了数组,存储空间是连续的,读写同一片存储空间,而且可能涉及到元素的移动,只能用同一把锁来控制访问,而LinkedBlockingQueue使用的是链表,存储空间是不连续的,元素的异动只是指针的变更,读写锁自然可以分离。

两个Condition分别使用在不同场景下:

notEmpty和takeLock搭配,获取了takeLock还不够,还必须满足notEmpty的条件。

notFull和putLock搭配,获取了putLock还不够,还必须满足notFull的条件。

再来看看put方法。

LinkedBlockingQueue_第3张图片
put方法
LinkedBlockingQueue_第4张图片
enqueue方法

代码比较简单明了,只说三点:

1. 不允许Null值存入链表。

2. 入队enqueue方法有两步,第一,把尾指针的next指向新加入的Node,第二,把尾指针重新指向新加入的Node。这个方法是线程安全的,因为它是在获得lock后执行的

3. 局部变量c是从-1开始的,代表元素还没有成功设置。

类似的,我们也可以分析take方法,这里就不在赘述。可以稍微看下出队的方法。

LinkedBlockingQueue_第5张图片
dequeue方法

首先,把头结点的next指向自己,这样就没有GC Roots可达了,接着把第一个节点元素置空,好腾出来做头结点。最后返回置空前的元素值。

LinkedBlockingQueue就分析到这里。

你可能感兴趣的:(LinkedBlockingQueue)