LinkedBlockingQueue是一個基于鏈表的阻塞隊列,實現了BlockingQueue、java.io.Serializable接口繼承自AbstractQueue
創建:
//當隊列中沒有任何元素的時候,此時隊列的頭部就等于隊列的尾部,指向的是同一個節點,并且內容為null
public LinkedBlockingQueue(int capacity) {
if (capacity <= 0) throw new IllegalArgumentException();
this.capacity = capacity;
last = head = new Node<E>(null);
}
//無參構造,默認使用int的最大值作為capacity的值
public LinkedBlockingQueue() {
this(Integer.MAX_VALUE);
}
//將一個集合中的元素全部入隊列。
public LinkedBlockingQueue(Collection<? extends E> c) {
this(Integer.MAX_VALUE);
final ReentrantLock putLock = this.putLock;
//獲取鎖
putLock.lock(); // Never contended, but necessary for visibility
try {
//迭代集合中的每一個元素,讓其入隊列,并且更新一下當前隊列中的元素數量
int n = 0;
for (E e : c) {
if (e == null)
throw new NullPointerException();
if (n == capacity)
throw new IllegalStateException("Queue full");
//參考下面的enqueue分析
enqueue(new Node<E>(e));
++n;
}
count.set(n);
} finally {
//釋放鎖
putLock.unlock();
}
}
數據元素操作:
//我們看到是一個鏈表,里面每個節點都是一個內部類Node,所有的元素都通過Node類來進行存儲
static class Node<E> {
E item;
Node<E> next;
Node(E x) { item = x; }
}
//創建一個節點,并加入鏈表尾部,入隊
private void enqueue(Node<E> node) {
//把node賦給當前的最后一個節點的下一個節點,然后在將node設為最后一個節點
last = last.next = node;
}
//出隊
private E dequeue() {
Node<E> h = head;//獲取頭節點:x==null
Node<E> first = h.next;//將頭節點的下一個節點賦值給first
h.next = h; // 將當前將要出隊的節點置null(為了使其做head節點做準備
head = first;//將當前將要出隊的節點作為了頭節點
E x = first.item;//獲取出隊節點的值
first.item = null;//將出隊節點的值置空
return x;
}
重要參數:
//AtomicInteger 一個提供原子操作的Integer的類,用來計算現在隊列有多少個元素
//解決在入隊或出隊時并發修改元素數量
private final AtomicInteger count = new AtomicInteger(0);
//元素出隊入隊時線程所獲取的重入鎖
private final ReentrantLock takeLock = new ReentrantLock();
private final ReentrantLock putLock = new ReentrantLock();
//當隊列為空時,讓從隊列中獲取元素的線程處于掛起狀態
private final Condition notEmpty = takeLock.newCondition();
//當隊列為空時,讓元素入隊列的的線程處于掛起狀態
private final Condition notFull = putLock.newCondition();
入隊:
public void put(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
// Note: convention in all put/take/etc is to preset local var
int c = -1;
Node<E> node = new Node(e);
//當成員變量被其他線程改變時,因為在方法內部重新引用并用final修飾,保證在一次操作內數據是一致的?
final ReentrantLock putLock = this.putLock;
final AtomicInteger count = this.count;
//執行可中斷的鎖獲取操作
putLock.lockInterruptibly();
try {
//當隊列的容量到底最大時,此時線程將處于等待狀態 ?為什么要使用while
while (count.get() == capacity) {
notFull.await();
}
//讓元素排入隊列的末尾
enqueue(node);
//更新隊列中的元素個數.此處的count.getAndIncrement()方法會更新元素個數并返回舊值
c = count.getAndIncrement();
//如果添加元素后的容量,還小于指定容量,說明至少還可以再插一個元素
if (c + 1 < capacity)
notFull.signal();
} finally {
//釋放鎖
putLock.unlock();
}
//注意!!!這個c的值就count容量的舊值,c == 0時說明之前的隊列是空隊列,即出隊列=的線程都處于等待狀態
//上邊增加了一個新的元素,隊列不為空,就會喚醒正在等待獲取元素的線程
if (c == 0)
signalNotEmpty();
}
//喚醒正在等待獲取元素的線程
private void signalNotEmpty() {
final ReentrantLock takeLock = this.takeLock;
takeLock.lock();
try {
//通過notEmpty喚醒獲取元素的線程
notEmpty.signal();
} finally {
takeLock.unlock();
}
}
出隊:
public E take() throws InterruptedException {
E x;
int c = -1;
final AtomicInteger count = this.count;
final ReentrantLock takeLock = this.takeLock;
//獲取鎖
takeLock.lockInterruptibly();
try {
//當隊列為空時,則讓當前線程處于等待
while (count.get() == 0) {
notEmpty.await();
}
//完成元素的出隊列
x = dequeue();
//更新隊列中的元素個數.
c = count.getAndDecrement();
//當前隊列中元素數量大于1,喚醒線程,繼續執行出隊操作
if (c > 1)
notEmpty.signal();
} finally {
//釋放鎖
takeLock.unlock();
}
//c==capaitcy的時候,在執行此次出隊操作完成之前隊列已經滿了,去喚醒入隊操作的線程進行插入操作
if (c == capacity)
signalNotFull();
return x;
}
private void signalNotFull() {
final ReentrantLock putLock = this.putLock;
putLock.lock();
try {
notFull.signal();
} finally {
putLock.unlock();
}
}
補充:
AtomicInteger
對于一個Integer線程安全的操作。
//當前值+1,采用無限循環,直到+1成功為止
//返回的是舊值
public final int getAndIncrement() {
for (;;) {
int current = get();//獲取當前值
int next = current + 1;//當前值+1
if (compareAndSet(current, next))//基于CAS賦值
return current;
}
}
//當前值-1,采用無限循環,直到-1成功為止
//返回舊值
public final int getAndDecrement() {
for (;;) {
int current = get();
int next = current - 1;
if (compareAndSet(current, next))
return current;
}
}
compareAndSet這個方法多見于并發控制中,簡稱CAS(Compare And Swap),意思是如果valueOffset位置包含的值與expect值相同,則更新valueOffset位置的值為update,并返回true,否則不更新,返回false。
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}