package org.googlecode.threadpool;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import org.googlecode.threadpool.CentralExecutor.NamedThreadFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 简单的任务分发类,支持根据业务资源分配模型来分配线程资源,当前支持两类 1. 根据某一类key可以预留多少资源独享。 2.
* 根据某一类key可以限制最多使用多少资源。
*
* @author fangweng
*/
public class JobDispatcher implements Runnable {
private static final Logger log = LoggerFactory.getLogger(JobDispatcher.class);
private TaskCentralExecutor threadPool;// 内部线程池
private JobThreadWeightModel[] jobThreadWeightModel;// 内置资源分配线程池模型,可运行期动态构建
private Map<String, AtomicInteger> counterPool;// 记录每一个设置了资源分配模型的资源所占用的私有线程数(如果是limit就和defaultCounterPool保持一致)
private Map<String, TaskBufferQueue> jobQueuePool;// 不同的资源分配模型配置key都有自己的队列结构,默认的模型采用default。
private Map<String, AtomicInteger> defaultCounterPool;// 用于记录每一个设置了资源分配模型的资源所占用的真实线程数。(包括私有和共有的)
private TaskQuotaAllocator quotaFactory;// 任务阀值
private AtomicInteger defaultCounter;// 默认线程消耗数量,totalcounter-各个私有线程消耗
private AtomicInteger totalCounter;// 所有线程消耗数量
private int maximumPoolSize = 200;
private int corePoolSize = 50;
private int maximumQueueSize = 1000;
private int maxQueueDispatcherSize = 2;
private PriorityBlockingQueue<JobFutureTask> futureTaskTTLList;// 用于check超时执行的线程,尝试取消
/**
* 保留型的资源配置,优先使用保留的资源
*/
private boolean privateUseFirst = true;
/**
* 任务失效时间,全局统一,单位秒
*/
private int jobTimeOut = 0;
private Thread timeoutChecker;
private boolean runFlag = true;
private ReentrantLock checkerLock;
private Condition hasJobCondition;
private boolean timeOutAfterExecute = false;// 是否从执行开始设置timeout时间
public boolean isTimeOutAfterExecute() {
return timeOutAfterExecute;
}
public void setTimeOutAfterExecute(boolean timeOutAfterExecute) {
this.timeOutAfterExecute = timeOutAfterExecute;
}
public PriorityBlockingQueue<JobFutureTask> getFutureTaskTTLList() {
return futureTaskTTLList;
}
public void setFutureTaskTTLList(
PriorityBlockingQueue<JobFutureTask> futureTaskTTLList) {
this.futureTaskTTLList = futureTaskTTLList;
}
public Map<String, TaskBufferQueue> getJobQueuePool() {
return jobQueuePool;
}
public int getMaxQueueDispatcherSize() {
return maxQueueDispatcherSize;
}
public int getJobTimeOut() {
return jobTimeOut;
}
public void setJobTimeOut(int jobTimeOut) {
this.jobTimeOut = jobTimeOut;
}
public void setMaxQueueDispatcherSize(int maxQueueDispatcherSize) {
this.maxQueueDispatcherSize = maxQueueDispatcherSize;
}
public JobThreshold getJobThreshold() {
return jobThreshold;
}
public void setJobThreshold(JobThreshold jobThreshold) {
this.jobThreshold = jobThreshold;
}
public boolean isPrivateUseFirst() {
return privateUseFirst;
}
public void setPrivateUseFirst(boolean privateUseFirst) {
this.privateUseFirst = privateUseFirst;
}
public int getDefaultQueueCounter() {
return jobQueuePool.get(DEFAULT_JOBQUEUE).size();
}
public TaskCentralExecutor getThreadPool() {
return threadPool;
}
public void setThreadPool(TaskCentralExecutor threadPool) {
this.threadPool = threadPool;
}
public void init() {
if (threadPool == null)
threadPool = new TaskCentralExecutor(corePoolSize,
maximumPoolSize, 0L, TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(maximumQueueSize),
new NamedThreadFactory("jobDispatcher_worker"), this);
defaultCounter = new AtomicInteger(0);
totalCounter = new AtomicInteger(0);
counterPool = new ConcurrentHashMap<String, AtomicInteger>();
defaultCounterPool = new ConcurrentHashMap<String, AtomicInteger>();
jobQueuePool = new ConcurrentHashMap<String, TaskBufferQueue>();
futureTaskTTLList = new PriorityBlockingQueue<JobFutureTask>();
timeoutChecker = new Thread(this, "jobDispatcher-TimeoutChecker");
timeoutChecker.setDaemon(true);
timeoutChecker.start();
checkerLock = new ReentrantLock();
hasJobCondition = checkerLock.newCondition();
// 默认无key的任务队列
TaskBufferQueue q = new TaskBufferQueue(DEFAULT_JOBQUEUE, maximumQueueSize, this);
jobQueuePool.put(DEFAULT_JOBQUEUE, q);
jobThreshold = buildWeightModel(jobThreadWeightModel);
}
/**
* 运行期修改模型
*
* @param newJobThreadWeightModel
*/
public JobThreshold buildWeightModel(
JobThreadWeightModel[] newJobThreadWeightModel) {
this.jobThreadWeightModel = newJobThreadWeightModel;
JobThreshold newJobThreshold = new JobThreshold();
newJobThreshold.setDefaultThreshold(maximumPoolSize);
if (newJobThreadWeightModel != null
&& newJobThreadWeightModel.length > 0) {
for (JobThreadWeightModel j : newJobThreadWeightModel) {
try {
// 构建设置资源分配模型所需要的附属对象
if (counterPool.get(j.getKey()) == null) {
counterPool.put(j.getKey(), new AtomicInteger(0));
TaskBufferQueue q = new TaskBufferQueue(j.getKey(), maximumQueueSize,
this);
jobQueuePool.put(j.getKey(), q);
defaultCounterPool
.put(j.getKey(), new AtomicInteger(0));
}
if (j.getValue() == 0)
continue;
if (j.getType().equals(
JobThreadWeightModel.WEIGHT_MODEL_LIMIT)) {
newJobThreshold.getThresholdPool().put(j.getKey(),
j.getValue());
} else if (j.getType().equals(
JobThreadWeightModel.WEIGHT_MODEL_LEAVE)) {
newJobThreshold.getThresholdPool().put(j.getKey(),
j.getValue());
newJobThreshold.setDefaultThreshold(newJobThreshold
.getDefaultThreshold()
- j.getValue());
} else {
log.error(new StringBuilder(
"thread weight config type:").append(
j.getType()).append(" key:").append(j.getKey())
.append(" value:").append(j.getValue()).append(
" not support!"));
}
} catch (Exception ex) {
log.error("create jobWeightModels: " + j.getKey()
+ " error!", ex);
}
}
if (newJobThreshold.getDefaultThreshold() <= 0)
throw new RuntimeException(
"total leave resource > total resource...");
for (JobThreadWeightModel j : newJobThreadWeightModel) {
try {
if (j.getValue() == 0)
continue;
if (j.getType().equals(
JobThreadWeightModel.WEIGHT_MODEL_LIMIT)) {
if (newJobThreshold.getThresholdPool().get(j.getKey()) > newJobThreshold
.getDefaultThreshold())
newJobThreshold.getThresholdPool().put(j.getKey(),
-newJobThreshold.getDefaultThreshold());
else
newJobThreshold.getThresholdPool().put(
j.getKey(),
-newJobThreshold.getThresholdPool().get(
j.getKey()));
}
} catch (Exception ex) {
log.error("create jobWeightModels: " + j.getKey()
+ " error!", ex);
}
}
}
return newJobThreshold;
}
/**
* 兼容普通的runnable的提交
*
* @param job
*/
public void execute(Runnable job) {
if (job instanceof Task)
execute((Task) job);
else
threadPool.execute(job);
}
/**
* 检查是否有资源可用, 注意检查过程已经有对资源数值作修改的动作,不可重复调用,避免资源泄露
*
* @param task
* @return
*/
public boolean checkJobResource(Task task) {
boolean hasResource = false;
// 第一层做总量判断,同时锁定总资源
if (totalCounter.incrementAndGet() > this.maximumPoolSize) {
totalCounter.decrementAndGet();
return false;
}
String key = task.getKey();
Integer threshold = null;
if (key != null)
threshold = jobThreshold.getThresholdPool().get(key);
if (key == null || threshold == null) {
// 使用默认资源,计数器累加比较判断是否有资源
if (defaultCounter.incrementAndGet() > jobThreshold
.getDefaultThreshold()) {
defaultCounter.decrementAndGet();
} else {
hasResource = true;
}
} else {
AtomicInteger counter = counterPool.get(key);
if (threshold > 0) {// leave mode
// leave模式下,可以选择先用私有的资源
if (privateUseFirst) {
if (counter.incrementAndGet() > threshold) {
counter.decrementAndGet();
// 私有的用完了话,考虑用共有的
if (defaultCounter.incrementAndGet() > jobThreshold
.getDefaultThreshold()) {
defaultCounter.decrementAndGet();
} else {
hasResource = true;
}
} else {
hasResource = true;
}
} else {
// 先用公有的,如果没有资源在判断是否有私有的
if (defaultCounter.incrementAndGet() > jobThreshold
.getDefaultThreshold()) {
defaultCounter.decrementAndGet();
if (counter.incrementAndGet() > threshold)
counter.decrementAndGet();
else
hasResource = true;
} else {
hasResource = true;
}
}
} else {// limit模式下,检查是否超过了阀值,limit得阀值设置为负数用于和leave区分
if (counter.incrementAndGet() > -threshold) {
counter.decrementAndGet();
} else {
if (defaultCounter.incrementAndGet() > jobThreshold
.getDefaultThreshold()) {
defaultCounter.decrementAndGet();
counter.decrementAndGet();
} else {
hasResource = true;
}
}
}
}
if (!hasResource)
totalCounter.decrementAndGet();
return hasResource;
}
/**
* 提交任务
*/
public void execute(Task task) {
boolean hasResource = checkJobResource(task);
// 注意,如果设置了jobtimeout,那么job自身进入时如果已经设置timeout将会被覆盖
if (jobTimeOut > 0 && !timeOutAfterExecute) {
task.setTimeOut(System.currentTimeMillis() + jobTimeOut * 1000);
}
if (hasResource) {
// 注意,如果设置了jobtimeout,那么job自身进入时如果已经设置timeout将会被覆盖
if (jobTimeOut > 0 && timeOutAfterExecute) {
task.setTimeOut(System.currentTimeMillis() + jobTimeOut * 1000);
}
innExecute(task);
} else {
pushJob(task);
}
}
public JobFutureTask innExecute(Task task) {
JobFutureTask ftask = null;
if (task.getTimeOut() > 0) {
ftask = new JobFutureTask(task, null);
threadPool.execute(ftask);
} else
threadPool.execute(task);
return ftask;
}
public JobThreadWeightModel[] getJobThreadWeightModel() {
return jobThreadWeightModel;
}
public void setJobThreadWeightModel(
JobThreadWeightModel[] jobThreadWeightModel) {
this.jobThreadWeightModel = jobThreadWeightModel;
}
public void setJobThreadWeightModel(
List<JobThreadWeightModel> jobThreadWeightModel) {
this.jobThreadWeightModel = jobThreadWeightModel
.toArray(new JobThreadWeightModel[0]);
}
public int getMaximumPoolSize() {
return maximumPoolSize;
}
public void setMaximumPoolSize(int maximumPoolSize) {
this.maximumPoolSize = maximumPoolSize;
}
public int getMaximumQueueSize() {
return this.maximumQueueSize;
}
public void setMaximumQueueSize(int maximumQueueSize) {
this.maximumQueueSize = maximumQueueSize;
}
public Map<String, AtomicInteger> getCounterPool() {
return counterPool;
}
public Map<String, Integer> getThresholdPool() {
return jobThreshold.getThresholdPool();
}
public int getDefaultThreshold() {
return jobThreshold.getDefaultThreshold();
}
public AtomicInteger getDefaultCounter() {
return defaultCounter;
}
public AtomicInteger getTotalCounter() {
return totalCounter;
}
public Map<String, AtomicInteger> getDefaultCounterPool() {
return defaultCounterPool;
}
public int getCorePoolSize() {
return corePoolSize;
}
public void setCorePoolSize(int corePoolSize) {
this.corePoolSize = corePoolSize;
}
/**
* 任务入队列
*
* @param task
*/
public void pushJob(Task task) {
TaskBufferQueue taskBufferQueue = getJobQueue(task);
if (!taskBufferQueue.offer(task)) {// 补偿job
throw new RuntimeException("can't submit job, queue full...");
}
}
/**
* 根据job类型获取对应的队列
*
* @param task
* @return
*/
public TaskBufferQueue getJobQueue(Task task) {
TaskBufferQueue taskBufferQueue;
// 采用默认的
if (task.getKey() == null
|| (task.getKey() != null && !jobQueuePool.containsKey(task
.getKey()))) {
taskBufferQueue = jobQueuePool.get(DEFAULT_JOBQUEUE);
} else {
taskBufferQueue = jobQueuePool.get(task.getKey());
}
return taskBufferQueue;
}
/**
* 线程执行前的操作
*
* @param task
*/
public void beforeExecuteJob(Task task) {
// 用于统计默认线程中不同的请求消耗的线程数
if (task.getKey() != null
&& defaultCounterPool.containsKey(task.getKey())) {
defaultCounterPool.get(task.getKey()).incrementAndGet();
}
// 用于超时检查
if (task instanceof JobFutureTask) {
futureTaskTTLList.add((JobFutureTask) task);
notifyHasTimeOutJob();
}
}
/**
* 释放线程时对于各种计数器做递减
*
* @param task
*/
public void releaseJob(Task task) {
// 用于删除
if (task instanceof JobFutureTask) {
futureTaskTTLList.remove((JobFutureTask) task);
}
// 需要增加notify的代码
String key = task.getKey();
this.getTotalCounter().decrementAndGet();
if (this.getCounterPool().size() == 0 || key == null) {
this.getDefaultCounter().decrementAndGet();
} else {
AtomicInteger counter = this.getCounterPool().get(key);
if (counter != null) {
if (defaultCounterPool.get(key) != null) {
defaultCounterPool.get(key).decrementAndGet();
}
// leave先还私有的
if (counter.decrementAndGet() < 0) {
counter.incrementAndGet();
this.getDefaultCounter().decrementAndGet();
} else {
Integer size = this.getThresholdPool().get(key);
if (size == null || (size != null && size < 0)) { // limit
// mode
// (use
// default)
// counter.decrementAndGet();
this.getDefaultCounter().decrementAndGet();
} else { // leave mode (use itself)
// nothing to do
}
}
} else {
this.getDefaultCounter().decrementAndGet();
}
}
// 释放资源信号,必须放在最后
TaskBufferQueue taskBufferQueue = getJobQueue(task);
taskBufferQueue.notifyHasResource();
}
/**
* 通知有任务已经入队列
*/
public void notifyHasTimeOutJob() {
boolean flag = false;
try {
flag = checkerLock.tryLock(50, TimeUnit.MILLISECONDS);
if (flag)
hasJobCondition.signalAll();
} catch (InterruptedException ie) {
// do nothing;
} catch (Exception ex) {
log.error(ex);
} finally {
if (flag)
checkerLock.unlock();
}
}
/**
* 队列中无任务的阻塞消息
*
* @param waittime
*/
public void blockNoTimeOutJob(long waittime) {
if (waittime < 0)
return;
boolean flag = checkerLock.tryLock();
if (flag) {
try {
hasJobCondition.await(waittime, TimeUnit.MILLISECONDS);
} catch (InterruptedException ie) {
// do nothing;
} catch (Exception ex) {
log.error("block Queue error.", ex);
} finally {
checkerLock.unlock();
}
}
}
@Override
public void run() {
while (runFlag) {
try {
JobFutureTask task = futureTaskTTLList.peek();
if (task == null) {
blockNoTimeOutJob(60000);
} else {
do {
if (System.currentTimeMillis() > task.getTimeOut()) {
task.cancel(true);
futureTaskTTLList.remove(task);
} else {
break;
}
task = futureTaskTTLList.peek();
} while (task != null);
if (task != null)
blockNoTimeOutJob(task.getTimeOut()
- System.currentTimeMillis());
}
} catch (Exception ex) {
log.error(ex);
}
}
}
}