前言
前面我總結了一下關於BlockingQueue和BlockingQueue實現類的相關知識點,現在接下來看concurrent包的另一個接口BlockingDeque,BlockingDeque 接口表示一個線程安放入和提取實例的雙端隊列。就是說兩段都可以進出的,實際上和單端的也差不多,就是單端變雙端。
拋異常 | 特定值 | 阻塞 | 超時 |
---|---|---|---|
插入 | addFirst(o) | offerFirst(o) | putFirst(o) |
移除 | removeFirst(o) | pollFirst(o) | takeFirst(o) |
檢查 | getFirst(o) | peekFirst(o) |
實現類
- LinkedBlockingDeque
接口源碼
/*
我把註釋全刪了
*/
package java.util.concurrent;
import java.util.*;
// Deque繼承了Queue
public interface BlockingDeque<E> extends BlockingQueue<E>, Deque<E> {
void addFirst(E e);
void addLast(E e);
boolean offerFirst(E e);
boolean offerLast(E e);
void putFirst(E e) throws InterruptedException;
void putLast(E e) throws InterruptedException;
boolean offerFirst(E e, long timeout, TimeUnit unit)
throws InterruptedException;
boolean offerLast(E e, long timeout, TimeUnit unit)
throws InterruptedException;
E takeFirst() throws InterruptedException;
E takeLast() throws InterruptedException;
E pollFirst(long timeout, TimeUnit unit)
throws InterruptedException;
E pollLast(long timeout, TimeUnit unit)
throws InterruptedException;
boolean removeFirstOccurrence(Object o);
boolean removeLastOccurrence(Object o);
// *** BlockingQueue methods ***
// 所以以下是BlockingQueue相關的方法
boolean add(E e);
boolean offer(E e);
void put(E e) throws InterruptedException;
boolean offer(E e, long timeout, TimeUnit unit)
throws InterruptedException;
E remove();
E poll();
E take() throws InterruptedException;
E poll(long timeout, TimeUnit unit)
throws InterruptedException;
E element();
E peek();
boolean remove(Object o);
public boolean contains(Object o);
public int size();
Iterator<E> iterator();
// *** Stack methods ***
void push(E e);
}
LinkedBlockingQueue
這個實現類只有一個,我就不另外開一章來講了,就看看這個就好了。
怎麼用?
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;
public class Main22 {
public static void main(String[] args) {
BlockingDeque<Integer> bd = new LinkedBlockingDeque<>();
Pro pro = new Pro(bd);
Con1 con = new Con1(bd);
pro.start();
con.start();
}
}
class Pro extends Thread {
private BlockingDeque<Integer> bd;
public Pro(BlockingDeque<Integer> bd) {
this.bd = bd;
}
@Override
public void run() {
try {
bd.putFirst(1);
// 不加這個延遲,幾乎是一個順序操作
Thread.sleep(2);
bd.putFirst(2);
bd.putFirst(3);
System.out.println(bd.toString());
System.out.println(Thread.currentThread().getName() + " " + bd.takeFirst());
System.out.println(bd.toString());
System.out.println(Thread.currentThread().getName() + " " + bd.takeLast());
System.out.println(bd.toString());
System.out.println(Thread.currentThread().getName() + " " + bd.take());
bd.putFirst(4);
bd.putFirst(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class Con1 extends Thread {
private BlockingDeque<Integer> bd;
public Con1(BlockingDeque<Integer> bd) {
this.bd = bd;
}
@Override
public void run() {
try {
bd.putLast(11);
Thread.sleep(2);
bd.putLast(22);
bd.putLast(33);
System.out.println(bd.toString());
System.out.println(Thread.currentThread().getName() + " " + bd.takeFirst());
System.out.println(bd.toString());
System.out.println(Thread.currentThread().getName() + " " + bd.takeLast());
System.out.println(bd.toString());
System.out.println(Thread.currentThread().getName() + " " + bd.take());
bd.putLast(44);
bd.putLast(55);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
結果
[3, 2, 1, 11]
Thread-0 3
[2, 1, 11]
Thread-0 11
[2, 1]
Thread-0 2
[5, 4, 1, 22, 33]
Thread-1 5
[4, 1, 22, 33]
Thread-1 33
[4, 1, 22]
Thread-1 4
看看源碼
public void putFirst(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
// 需要包裝一個Node
Node<E> node = new Node<E>(e);
final ReentrantLock lock = this.lock;
lock.lock();
try {
while (!linkFirst(node))
notFull.await();
} finally {
lock.unlock();
}
}
private boolean linkFirst(Node<E> node) {
// assert lock.isHeldByCurrentThread();
// 如果比容量大返回false
if (count >= capacity)
return false;
// 否則就把節點掛在最前面
Node<E> f = first;
node.next = f;
first = node;
if (last == null)
last = node;
else
f.prev = node;
++count;
notEmpty.signal();
return true;
}
// 沒有指定容量就指定容量爲Max Integer
public LinkedBlockingDeque() {
this(Integer.MAX_VALUE);
}
// 如果指定了容量,就以指定容量爲capacity
public LinkedBlockingDeque(int capacity) {
if (capacity <= 0) throw new IllegalArgumentException();
this.capacity = capacity;
}
// 與put相似,不過是相反過程
public E takeLast() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lock();
try {
E x;
while ( (x = unlinkLast()) == null)
notEmpty.await();
return x;
} finally {
lock.unlock();
}
}
private E unlinkLast() {
// assert lock.isHeldByCurrentThread();
Node<E> l = last;
if (l == null)
return null;
Node<E> p = l.prev;
E item = l.item;
l.item = null;
l.prev = l; // help GC
last = p;
if (p == null)
first = null;
else
p.next = null;
--count;
notFull.signal();
return item;
}
後記
其實這個BlockingDeque並不算很難,這只是滿足了一種需求而創造出來的,實質上還是屬於BlockingQueue範疇的東西。