package com.slh;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**阻塞队列
* @Author SLH
* @create 2021/7/30 9:57
*/
@Slf4j
public class BlockingQueue<T> {
private final Deque<T> deque = new ArrayDeque<>();
private final int capacity;
private final Lock lock = new ReentrantLock();
private final Condition fullWaitSet = lock.newCondition();
private final Condition emptyWaitSet = lock.newCondition();
public BlockingQueue(int capacity) {
this.capacity = capacity;
}
/**获取阻塞队列中的任务
* 超时等待 FIFO原则
* @return 阻塞队列中的任务
*/
public T poll(int waitTime, TimeUnit unit){
lock.lock();
long time = unit.toNanos(waitTime);
try{
while(deque.isEmpty()){
try {
if(time <= 0){
return null;
}
time = emptyWaitSet.awaitNanos(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
T res = deque.removeFirst();
fullWaitSet.signal();
return res;
}finally {
lock.unlock();
}
}
/**
* 获取阻塞队列中的任务 FIFO原则
* @return 返回阻塞队列队头的元素
*/
public T take() {
lock.lock();
try {
while (deque.isEmpty()) {
try {
emptyWaitSet.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
T res = deque.removeFirst();
fullWaitSet.signal();
return res;
} finally {
lock.unlock();
}
}
/**
* 向阻塞队列中添加任务 FIFO原则
* @param task 等待执行的任务
* @return 0:表示添加陈工 -1:表示添加失败
*/
public int put(T task){
lock.lock();
try{
while(deque.size() == capacity){
try {
fullWaitSet.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
deque.push(task);
emptyWaitSet.signal();
return 0;
}finally {
lock.unlock();
}
}
/**
*
* @param task 向阻塞队列中添加的任务
* @param waitTime 超时时间,超过该时间后将不再继续等待
* @param unit 超时时间的单位
* @return 0:表示添加陈工 -1:表示添加失败
*/
public int offer(T task, long waitTime, TimeUnit unit){
lock.lock();
try{
long time = unit.toNanos(waitTime);
while(deque.size() == capacity){
try {
if(time <= 0){
return -1;
}
time = fullWaitSet.awaitNanos(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
deque.push(task);
emptyWaitSet.signal();
return 0;
}finally {
lock.unlock();
}
}
}