/**
*
*/
package org.googlecode.threadpool;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import org.googlecode.threadpool.util.NamedThreadFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Task 没有资源执行,将进入等待队列
* 这里有一个优先级的问题需要考虑:如果同一类型的主键具有相同的过期时间,则使用LinkedBlockingQueue
* 如果具有不同的过期时间,则需要使用优先级表
* @author zhongfeng
*
*/
public class BufferQueue {
private static final Logger LOG = LoggerFactory
.getLogger(BufferQueue.class);
/**
* 默认缓存对列大小
*/
private static final int DEFAULT_QUEUE_SIZE = 500;
/**
* 缓存任务提交线程命名前缀
*/
private static final String BUFFER_QUEUE_THREAD_PREFIEX = "BufferQueueThread-";
/**
* 任务主键
*/
private final String taskKey;
/**
* 缓存队列大小
*/
private final int maximumQueueSize;
/**
* 内部队列
*/
private BlockingQueue<RunnableTask> taskBufferQueue;
/**
* 缓存任务提交线程
*/
private ExecutorService exec;
/**
*
*/
private ReentrantLock lock = new ReentrantLock();
/**
* 有资源释放的Condition
*/
private Condition hasResource = lock.newCondition();
/**
* 有新任务加入的Condition
*/
private Condition hasJob = lock.newCondition();
/**
* @param taskKey
* @param maximumQueueSize
*/
private BufferQueue(String taskKey, int maximumQueueSize) {
this.taskKey = taskKey;
this.maximumQueueSize = maximumQueueSize;
this.taskBufferQueue = new LinkedBlockingQueue<RunnableTask>(
maximumQueueSize);
this.exec = Executors.newSingleThreadExecutor(new NamedThreadFactory(
BUFFER_QUEUE_THREAD_PREFIEX + taskKey, false));
}
/**
* 开启缓存任务提交,在queue创建完毕后开启
*
* @param centralExecutor 核心业务主线程池
* @param taskQuotaAllocator 配额资源管理器
*/
public void startQueueTaskSubmit(TaskCentralExecutor centralExecutor) {
exec
.submit(new BufferTaskSubmitter(centralExecutor));
}
public void stop() {
taskBufferQueue.clear();
try {
exec.awaitTermination(5000L, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
exec.shutdownNow();
}
/**
* 任务尝试入队列
*
* @param job
* @return
*/
public boolean addTask(RunnableTask task) {
LOG.debug("AddTask:Q:{}, Task: {}",getTaskKey(),task);
boolean result = taskBufferQueue.offer(task);
if (result) {
notifyHasJob();
}
return result;
}
public boolean isEmpty() {
return taskBufferQueue.isEmpty();
}
/**
* 通知有任务已经入队列
*/
private void notifyHasJob() {
lock.lock();
try {
hasJob.signalAll();
} finally {
lock.unlock();
}
}
/**
* 通知外部有资源可以执行任务
*/
public void notifyHasResource() {
boolean flag = lock.tryLock();
try {
if (flag)
hasResource.signalAll();
} finally {
if (flag)
lock.unlock();
}
}
/**
* 队列中无任务的阻塞消息
*
* @param waittime
*/
private void blockNoJob(long waittime) {
lock.lock();
try {
hasJob.await(waittime, TimeUnit.MILLISECONDS);
} catch (InterruptedException ie) {
// do nothing;
} finally {
lock.unlock();
}
}
/**
* 外部无可执行资源阻塞消息
*
* @param waittime
*/
private void blockNoResource(long waittime) {
lock.lock();
try {
hasResource.await(waittime, TimeUnit.MILLISECONDS);
} catch (InterruptedException ie) {
// do nothing;
} finally {
lock.unlock();
}
}
private class BufferTaskSubmitter implements Runnable {
private static final int WAIT_BLOCK_TIME = 5000;
private TaskCentralExecutor centralExecutor;
public BufferTaskSubmitter(TaskCentralExecutor centralExecutor) {
this.centralExecutor = centralExecutor;
}
public void run() {
while (!Thread.currentThread().isInterrupted()) {
if (taskBufferQueue.isEmpty()) {
blockNoJob(WAIT_BLOCK_TIME);// 如果没有任务就阻塞1秒钟
continue;
}
RunnableTask task = taskBufferQueue.peek();
// 判断是否有超时情况
if (task.isExpire()) {
taskBufferQueue.poll();
LOG.debug("Task is Expire. Discard it. Task:{}",task);
continue;
}
// 判断是否有资源,并且会先并发减去资源
if (centralExecutor.acquireResource(task)) {
// 如果有资源,弹出队列,执行任务,计数器递减
taskBufferQueue.poll();
centralExecutor.runTask(task);
} else {
LOG.debug("BufferQueue NO Resource: {}",getTaskKey());
blockNoResource(WAIT_BLOCK_TIME);// 如果没有资源就阻塞1秒钟
}
}// while
}// run
}
public static BufferQueue newInstance(String taskKey, int maximumQueueSize) {
return new BufferQueue(taskKey, maximumQueueSize);
}
public static BufferQueue newInstance(String taskKey) {
return newInstance(taskKey, DEFAULT_QUEUE_SIZE);
}
public String getTaskKey() {
return taskKey;
}
public int getMaximumQueueSize() {
return maximumQueueSize;
}
public BlockingQueue<RunnableTask> getTaskBufferQueue() {
return taskBufferQueue;
}
}