目录
前言
上篇文章中,用单锁实现了一个阻塞队列,可以思考下还有哪些地方可以完善和优化的点,这里提出一个可以完善的点和一个可以性能优化的点
- 可以完善的地方:新增方法,指定等待时间,如果超过指定时间就不再继续阻塞等待
- 可以性能优化的地方:单锁实现的方式,存放元素和取出元素的方法用的是同一把锁,当存放元素时不能取出元素,这样就有一定的性能损耗,可以使用两把锁来实现存放和取出元素相互不影响,提升程序性能
接口优化
接口中,新增两个方法
- 入队时,如果队列已满,最多等待指定时间后不再等待
- 出队时,如果队列已空,最多等待指定时间后不再等待
阻塞队列接口的完整定义如下:
java
package algorithm.blocking.queue;
import java.util.concurrent.TimeUnit;
/**
* 阻塞队列接口
*/
public interface BlockingQueue {
/**
* 入队:当队列满时,会一直阻塞等待到队列不满为止
*/
void put(Object e) throws InterruptedException;
/**
* 入队:可以指定最大等待时间
*/
boolean offer(Object e, long timeout, TimeUnit timeUnit) throws InterruptedException;
/**
* 出队:当队列空时,会一直阻塞等待到队列不空为止
*/
Object take() throws InterruptedException;
/**
* 出队:可以指定最大等待时间
*/
Object poll(long timeout, TimeUnit timeUnit) throws InterruptedException;
/**
* 队列中元素个数
*/
int size();
}
定义抽象类
java
package algorithm.blocking.queue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 定义基于双向链表实现阻塞队列的抽象类
*/
public abstract class AbstractLinkedListBlockingQueue implements BlockingQueue {
// 虚拟头节点
protected Node dummyHead;
// 虚拟尾节点
protected Node dummyTail;
// 元素个数
protected AtomicInteger size = new AtomicInteger();
// 默认最大容量
public static final int DEFAULT_MAX_CAPACITY = Integer.MAX_VALUE - 8;
// 最大容量
protected int maxCapacity;
@Override
public void put(Object e) throws InterruptedException {
if (e == null) {
throw new NullPointerException();
}
doEnter(e);
}
protected abstract void doEnter(Object e) throws InterruptedException;
@Override
public boolean offer(Object e, long timeout, TimeUnit timeUnit) throws InterruptedException {
if (e == null) {
throw new NullPointerException();
}
if (timeout <= 0) {
throw new IllegalArgumentException();
}
if (timeUnit == null) {
timeUnit = TimeUnit.MILLISECONDS;
}
return doEnter(e, timeout, timeUnit);
}
protected abstract boolean doEnter(Object e, long timeout, TimeUnit timeUnit) throws InterruptedException;
@Override
public Object take() throws InterruptedException {
Node node = doOut();
return node == null ? null : node.val;
}
protected abstract Node doOut() throws InterruptedException;
@Override
public Object poll(long timeout, TimeUnit timeUnit) throws InterruptedException {
if (timeout <= 0) {
throw new IllegalArgumentException();
}
if (timeUnit == null) {
timeUnit = TimeUnit.MILLISECONDS;
}
Node node = doOut(timeout, timeUnit);
return node == null ? null : node.val;
}
protected abstract Node doOut(long timeout, TimeUnit timeUnit) throws InterruptedException;
@Override
public int size() {
return size.get();
}
// 初始化虚拟头尾节点
protected void initDummyHeadTailNode() {
dummyHead = new Node();
dummyTail = new Node();
dummyHead.next = dummyTail;
dummyTail.prev = dummyHead;
}
// 尾部添加节点
protected void addLast(Object e) {
Node addNode = new Node(e);
Node prev = dummyTail.prev;
dummyTail.prev = addNode;
addNode.next = dummyTail;
addNode.prev = prev;
prev.next = addNode;
}
// 头部移除节点
protected Node removeFirst() {
Node removeNode = dummyHead.next;
Node next = dummyHead.next.next;
next.prev = dummyHead;
dummyHead.next = next;
removeNode.prev = null;
removeNode.next = null;
return removeNode;
}
// 数据节点
protected static class Node {
Object val;
Node prev;
Node next;
public Node() {
}
public Node(Object val) {
this.val = val;
}
public Node(Object val, Node prev, Node next) {
this.val = val;
this.prev = prev;
this.next = next;
}
}
}
实现类一:使用单锁来实现
java
package algorithm.blocking.queue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 基于链表和单锁方式实现的阻塞队列
*/
public class SingleLockLinkedListBlockingQueue extends AbstractLinkedListBlockingQueue {
// 定义一把锁
private final Lock lock = new ReentrantLock();
private final Condition putWaits = lock.newCondition();
private final Condition takeWaits = lock.newCondition();
public SingleLockLinkedListBlockingQueue() {
this.maxCapacity = DEFAULT_MAX_CAPACITY;
initDummyHeadTailNode();
}
// 实例化时指定最大容量
public SingleLockLinkedListBlockingQueue(int maxCapacity) {
this.maxCapacity = maxCapacity;
initDummyHeadTailNode();
}
@Override
protected void doEnter(Object e) throws InterruptedException {
lock.lock();
try {
while (size.get() == maxCapacity) {
// 队列已满,线程阻塞等待在putWaits
putWaits.await();
}
addLast(e);
size.getAndIncrement();
// 唤醒阻塞在takeWaits上的等待线程
takeWaits.signalAll();
} finally {
lock.unlock();
}
}
@Override
protected boolean doEnter(Object e, long timeout, TimeUnit timeUnit) throws InterruptedException {
lock.lock();
try {
timeout = timeUnit.toNanos(timeout);
while (size.get() == maxCapacity) {
if (timeout <= 0) {
return false;
}
timeout = putWaits.awaitNanos(timeout);
}
addLast(e);
size.getAndIncrement();
takeWaits.signalAll();
return true;
} finally {
lock.unlock();
}
}
@Override
protected Node doOut() throws InterruptedException {
lock.lock();
try {
while (size.get() == 0) {
// 队列中没有元素,线程阻塞等待在takeWaits
takeWaits.await();
}
Node outNode = removeFirst();
size.getAndDecrement();
// 唤醒阻塞在putWaits上的等待线程
putWaits.signalAll();
return outNode;
} finally {
lock.unlock();
}
}
@Override
protected Node doOut(long timeout, TimeUnit timeUnit) throws InterruptedException {
lock.lock();
try {
timeout = timeUnit.toNanos(timeout);
while (size.get() == 0) {
if (timeout <= 0) {
return null;
}
timeout = takeWaits.awaitNanos(timeout);
}
Node outNode = removeFirst();
size.getAndDecrement();
putWaits.signalAll();
return outNode;
} finally {
lock.unlock();
}
}
}
实现类二:使用两把锁来实现
java
package algorithm.blocking.queue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 基于链表和双锁方式实现的阻塞队列
*/
public class DoubleLockLinkedListBlockingQueue extends AbstractLinkedListBlockingQueue {
// 定义双锁
private final Lock putLock = new ReentrantLock();
private final Condition putWaits = putLock.newCondition();
private final Lock takeLock = new ReentrantLock();
private final Condition takeWaits = takeLock.newCondition();
public DoubleLockLinkedListBlockingQueue() {
this.maxCapacity = DEFAULT_MAX_CAPACITY;
initDummyHeadTailNode();
}
public DoubleLockLinkedListBlockingQueue(int maxCapacity) {
this.maxCapacity = maxCapacity;
initDummyHeadTailNode();
}
@Override
protected void doEnter(Object e) throws InterruptedException {
int count;
putLock.lock();
try {
while (size.get() == maxCapacity) {
// 队列已满,阻塞当前线程
putWaits.await();
}
// 入队
addLast(e);
count = size.getAndIncrement();
if (count < maxCapacity - 1) {
// 极联唤醒
putWaits.signal();
}
} finally {
putLock.unlock();
}
// 处于临界条件下,唤醒阻塞等待在takeWaits的线程
// 此处临界条件为:队列中的元素从无到有
if (count == 0) {
takeSignal();
}
}
private void takeSignal() {
takeLock.lock();
try {
takeWaits.signal();
} finally {
takeLock.unlock();
}
}
@Override
protected boolean doEnter(Object e, long timeout, TimeUnit timeUnit) throws InterruptedException {
int count;
putLock.lock();
try {
timeout = timeUnit.toNanos(timeout);
while (size.get() == maxCapacity) {
if (timeout <= 0) {
return false;
}
timeout = putWaits.awaitNanos(timeout);
}
addLast(e);
count = size.getAndIncrement();
if (count < maxCapacity - 1) {
putWaits.signal();
}
} finally {
putLock.unlock();
}
if (count == 0) {
takeSignal();
}
return true;
}
@Override
protected Node doOut() throws InterruptedException {
Node outNode;
int count;
takeLock.lock();
try {
while (size.get() == 0) {
// 队列为空,当前线程阻塞等待在takeWaits
takeWaits.await();
}
// 出队
outNode = removeFirst();
count = size.getAndDecrement();
if (count > 1) {
// 极联唤醒
takeWaits.signal();
}
} finally {
takeLock.unlock();
}
// 临界条件:队列从满到不满
if (count == maxCapacity) {
putSignal();
}
return outNode;
}
private void putSignal() {
putLock.lock();
try {
putWaits.signal();
} finally {
putLock.unlock();
}
}
@Override
protected Node doOut(long timeout, TimeUnit timeUnit) throws InterruptedException {
Node outNode;
int count;
takeLock.lock();
try {
timeout = timeUnit.toNanos(timeout);
while (size.get() == 0) {
if (timeout <= 0) {
return null;
}
timeout = takeWaits.awaitNanos(timeout);
}
outNode = removeFirst();
count = size.getAndDecrement();
if (count > 1) {
takeWaits.signal();
}
} finally {
takeLock.unlock();
}
if (count == maxCapacity) {
putSignal();
}
return outNode;
}
}