java并发编程之美 学习笔记
LinkedBlockingQueue
LinkedBlockingQueue使用独占锁
实现有界的阻塞队列
。
总体结构
public class LinkedBlockingQueue<E> extends AbstractQueue<E>
implements BlockingQueue<E>, java.io.Serializable {
static class Node<E> {
E item;
Node<E> next;
Node(E x) { item = x; }
}
transient Node<E> head;
private transient Node<E> last;
//takeLock同时只有一个线程可以从队列头获取元素 -- take,poll等方法调用时使用
private final ReentrantLock takeLock = new ReentrantLock();
//“读取”数据的前置条件
private final Condition notEmpty = takeLock.newCondition();
//putLock 同时只有一个线程可以向队列尾部添加元素 -- put,offer等方法调用时使用
private final ReentrantLock putLock = new ReentrantLock();
//“写入”数据的前置条件
private final Condition notFull = putLock.newCondition();
//队列元素个数
private final AtomicInteger count = new AtomicInteger();
}
构造函数
public LinkedBlockingQueue() {
this(Integer.MAX_VALUE);
}
public LinkedBlockingQueue(int capacity) {
if (capacity <= 0) throw new IllegalArgumentException();
this.capacity = capacity;
///初始化首、尾节点,让它们指向哨兵节点
last = head = new Node<E>(null);
}
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) {
//集合中不允许出现null元素
if (e == null)
throw new NullPointerException();
if (n == capacity)
throw new IllegalStateException("Queue full");
//入列--后续分析
enqueue(new Node<E>(e));
++n;
}
//更新count个数
count.set(n);
} finally {
putLock.unlock();
}
}
offer操作
向队列尾部插入一个元素,如果队列中有空闲则插入成功后返回 true,如果队列己满
则丢弃当前元素然后返回 false 。 如果 e 元素为 null 则抛出 Nul!PointerException 异常。 — 注意: 此方法是非阻塞
的。
public boolean offer(E e) {
if (e == null) throw new NullPointerException();
final AtomicInteger count = this.count;
//队列满了之后,直接返回false;
if (count.get() == capacity)
return false;
int c = -1;
Node<E> node = new Node<E>(e);
final ReentrantLock putLock = this.putLock;
putLock.lock();
try {
if (count.get() < capacity) {
//1.入列
enqueue(node);
c = count.getAndIncrement(); //count自增1
if (c + 1 < capacity)
//唤醒 因notFull而等待的线程,即notFull.await()等待的线程;
notFull.signal();
}
} finally {
putLock.unlock();
}
if (c == 0)
//2. c== 0,说明至少执行了: c = count.getAndIncrement();这行代码
//也间接说了, 向队列添加元素成功
signalNotEmpty();
return c >= 0;
}
//1.入列至队尾
private void enqueue(Node<E> node) {
// assert putLock.isHeldByCurrentThread();
// assert last.next == null;
last = last.next = node;
}
//2.激活因 notEmpty条件而等待的线程: 即notEmpty.await()线程
//注意这里用的是takeLock
private void signalNotEmpty() {
final ReentrantLock takeLock = this.takeLock;
takeLock.lock();
try {
notEmpty.signal();
} finally {
takeLock.unlock();
}
}
put
向队列尾部插入一个元素,如果队列中有空 闲则插入后直接返回,如果队列己满则阻 塞当前线程
,直到队列有空闲插入成功后返回。
public void put(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
int c = -1;
Node<E> node = new Node<E>(e);
final ReentrantLock putLock = this.putLock;
final AtomicInteger count = this.count;
putLock.lockInterruptibly();
try {
while (count.get() == capacity) {
//队列满了, 阻塞等待;
notFull.await();
}
//入列
enqueue(node);
c = count.getAndIncrement();
if (c + 1 < capacity)
notFull.signal();
} finally {
putLock.unlock();
}
if (c == 0)
signalNotEmpty();
}
poll
从队列头部获取并移除一个元素 , 如果队列为空则返回 null , 该方法是不阻塞
的 。
public E poll() {
final AtomicInteger count = this.count;
//如果队列为空,则直接返回null, 不阻塞;
if (count.get() == 0)
return null;
E x = null;
int c = -1;
final ReentrantLock takeLock = this.takeLock;
takeLock.lock();
try {
if (count.get() > 0) {
//1.出列
x = dequeue();
c = count.getAndDecrement();
if (c > 1)
notEmpty.signal();
}
} finally {
takeLock.unlock();
}
if (c == capacity)
//c == capacity, 说明至少进行了 c = count.getAndDecrement();
//2.此时容量为 capacity - 1, 唤醒notFull.await()
signalNotFull();
return x;
}
//1. 出列
private E dequeue() {
// assert takeLock.isHeldByCurrentThread();
// assert head.item == null;
Node<E> h = head;
Node<E> first = h.next;
h.next = h; // head.next设置为自身, 孤立节点
head = first; //将first设置为新head
E x = first.item;
first.item = null; //设置first.item = null ,即修改为 哨兵节点
return x;
}
private void signalNotFull() {
final ReentrantLock putLock = this.putLock;
putLock.lock();
try {
notFull.signal();
} finally {
putLock.unlock();
}
}
peek
获取队列头部元素但是不从队列里面移除它,如果 队列为空则返 回 null 。 该方法是不 阻塞的
。
public E peek() {
//如果队列为空,直接返回null -- 不阻塞
if (count.get() == 0)
return null;
final ReentrantLock takeLock = this.takeLock;
takeLock.lock();
try {
Node<E> first = head.next;
if (first == null)
return null;
else
return first.item;
} finally {
takeLock.unlock();
}
}
take
获取当前队列头部元素并从队列里面移除它 。 如果 队列为空则阻塞
当前线程直到队列
不为 空然后为止。
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();
if (c > 1)
notEmpty.signal();
} finally {
takeLock.unlock();
}
if (c == capacity)
signalNotFull();
return x;
}
remove
删除队列里指定元素,如果有则删除并返回ture,否则返回false.
public boolean remove(Object o) {
if (o == null) return false;
//双重加锁
fullyLock();
try {
//从队列从向尾部开始遍历
for (Node<E> trail = head, p = trail.next;
p != null;
trail = p, p = p.next) {
if (o.equals(p.item)) {
unlink(p, trail);
//找到返回true
return true;
}
}
//找不到返回false
return false;
} finally {
//双从释放锁 -- 与加锁顺序相反
fullyUnlock();
}
}
void fullyLock() {
putLock.lock();
takeLock.lock();
}
void fullyUnlock() {
takeLock.unlock();
putLock.unlock();
}
void unlink(Node<E> p, Node<E> trail) {
// 1 -> 2 -> 3 如果删除2
//2.item = null, 1 -> 3
p.item = null;
trail.next = p.next;
if (last == p)
//如果p是last,那么删除p之后,last为p之前的元素即trail;
last = trail;
if (count.getAndDecrement() == capacity)
//唤醒 notFull.await()线程
notFull.signal();
}
size
public int size() {
return count.get();
}
总结