/* * <p> * 版权: ©2011 * </p> */ package org.young.isocket.threadpool; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import org.glassfish.grizzly.monitoring.jmx.AbstractJmxMonitoringConfig; import org.glassfish.grizzly.monitoring.jmx.GrizzlyJmxManager; import org.glassfish.grizzly.monitoring.jmx.JmxObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.young.icore.annotation.PropertiesAnnotation; import org.young.icore.util.PropertiesLoaderUtils; import org.young.isocket.exception.ConfigException; import org.young.isocket.jmx.JobDispatcherJMX; import org.young.isocket.jmx.JobDispatcherProbe; import org.young.isocket.parse.AbstractXmlConfigParser; /** * <p> * 描述:线程控制类,主要控制线程是否可以提交任务 * </p> * * @see * @author yangjun2 * @email yangjun1120@gmail.com * */ public class JobDispatcher extends AbstractXmlConfigParser<JobThreadWeightModel> { private static final Logger logger = LoggerFactory.getLogger(JobDispatcher.class); private static final String CONFIG_FILE = "thread-weight-models.xml"; private static final String TAG_THREADWEIGHTMODEL = "threadweightmodel"; private static final String ARRTIBUTE_KEY = "key"; private static final String ARRTIBUTE_TYPE = "type"; public static final String DEFAULT_COUNTER = "defaultCounter"; public static final String TOTAL_COUNTER = "totalCounter"; public static final String DEFAULT_QUEUE_COUNTER = "defaultQueueCounter"; public static final String THREAD_POOL_CORE_SISE = "coreSize"; //核心线程数 public static final String THREAD_POOL_MAX_SIZE = "maxSize"; //允许的最大线程数 public static final String THREAD_POOL_ACTIVE_COUNT = "activeCount"; //主动执行任务的近似线程数 public static final String THREAD_POOL_COMPLETED_COUNT = "completedCount";//已完成执行的近似任务总数 public static final String THREAD_POOL_LARGEST_SIZE = "largestSize";//曾经同时位于池中的最大线程数 public static final String THREAD_POOL_CURRENT_SIZE = "currentSize"; //池中的当前线程数 public static final String THREAD_POOL_QUEUE_SIZE = "queueSize"; //此执行程序使用的任务队列数量 public static final String THREAD_WEIGHT_MODEL = "model";//资源分配线程池模型 public static final String MODEL_SNAPSHOT = "modelSnapShot";//资源分配线程池当天的一个快照 public static final String DEFAULT_JOBQUEUE = "_default_job_queue_";//默认没有key的job所在的Queue。 private boolean isStop = false; /** * 内部线程池 */ private JobThreadPoolExecutor threadPool; /** * 记录每一个设置了资源分配模型的资源所占用的私有线程数(如果是limit就和defaultCounterPool保持一致) */ private Map<String, AtomicInteger> counterPool; /** * 内置资源分配线程池模型,可运行期动态构建 */ private JobThreadWeightModel[] jobThreadWeightModel; /** * 不同的资源分配模型配置key都有自己的队列结构,默认的模型采用default. */ private Map<String, JobQueue> jobQueuePool; /** * 用于记录每一个设置了资源分配模型的资源所占用的真实线程数。(包括私有和共有的) */ private Map<String, AtomicInteger> defaultCounterPool; /** * 任务阀值 */ private JobThreshold jobThreshold; /** * 默认线程消耗数量,totalcounter-各个私有线程消耗 */ private AtomicInteger defaultCounter; /** * 所有线程消耗数量 */ private AtomicInteger totalCounter; /** * 最大队列数 */ @PropertiesAnnotation(name = "maxqueuesize", resource = "isocket-server.properties") private int maximumQueueSize = 500; /** * 最大线程数 */ @PropertiesAnnotation(name = "maxpoolsize", resource = "isocket-server.properties") private int maximumPoolSize = 100; /** * ThreadPool中的初始线程数 */ @PropertiesAnnotation(name = "corepoolsize", resource = "isocket-server.properties") private int corePoolSize = 50; /** * 保留型的资源配置,优先使用保留的资源 */ private boolean privateUseFirst = true; /** * ThreadPool probes */ protected final AbstractJmxMonitoringConfig<JobDispatcherProbe> monitoringConfig = new AbstractJmxMonitoringConfig<JobDispatcherProbe>( JobDispatcherProbe.class) { @Override public JmxObject createManagementObject() { return createJmxManagementObject(); } }; JmxObject createJmxManagementObject() { return new JobDispatcherJMX(this); } public AbstractJmxMonitoringConfig<JobDispatcherProbe> getMonitoringConfig() { return monitoringConfig; } public JobDispatcher() { init(); } public boolean isPrivateUseFirst() { return privateUseFirst; } public void setPrivateUseFirst(boolean privateUseFirst) { this.privateUseFirst = privateUseFirst; } @Override protected void doStartElement(XMLStreamReader r, Map<String, JobThreadWeightModel> map) { if (r.getLocalName().equals(TAG_THREADWEIGHTMODEL)) { String key = r.getAttributeValue(null, ARRTIBUTE_KEY); String type = r.getAttributeValue(null, ARRTIBUTE_TYPE); String value; try { value = r.getElementText(); } catch (XMLStreamException e) { throw new ConfigException("parse xml error.", e); } JobThreadWeightModel m = new JobThreadWeightModel(); m.setKey(key); m.setType(type); m.setValue(Integer.parseInt(value.trim())); if (logger.isDebugEnabled()) { logger.debug(new StringBuffer().append("loaded JobThreadWeightModel,key:").append(key).append(",type:") .append(type).append(",value:").append(value.trim()).toString()); } map.put(key, m); } } @Override protected void doEndElement(XMLStreamReader r, Map<String, JobThreadWeightModel> m) { super.dummy(); } /** * * <p> * 描述:初始化 * </p> * @param * @return * @throws * @see * @since %I% */ public void init() { isStop = false; //init attribute from properties PropertiesLoaderUtils.setPropertiesFields(this); if (threadPool == null) threadPool = new JobThreadPoolExecutor(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, JobQueue>(); //默认无key的任务队列 JobQueue q = new JobQueue(DEFAULT_JOBQUEUE, maximumQueueSize, this); jobQueuePool.put(DEFAULT_JOBQUEUE, q); //init job thread weight model from proprties Map<String, JobThreadWeightModel> parseMap = super.parse(CONFIG_FILE); setJobThreadWeightModel(parseMap.values().toArray(new JobThreadWeightModel[0])); jobThreshold = buildWeightModel(jobThreadWeightModel); //add jmx final GrizzlyJmxManager manager = GrizzlyJmxManager.instance(); JmxObject jmxTransportObject = getMonitoringConfig().createManagementObject(); //getMonitoringConfig().addProbes(//probes) manager.registerAtRoot(jmxTransportObject, "JobDispatcherJMX"); // ProbeNotifier.notifyThreadPoolStarted(this); } /** * 运行期修改模型 * @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)); JobQueue q = new JobQueue(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 { logger.error(new StringBuilder("thread weight config type:").append(j.getType()) .append(" key:").append(j.getKey()).append(" value:").append(j.getValue()) .append(" not support!").toString()); } } catch (Exception ex) { logger.error("create jobWeightModels: " + j.getKey() + " error!", ex); } } //判断保留模式的和是否超过预设的线程总数 if (newJobThreshold.getDefaultThreshold() <= 0) throw new ConfigException("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) { logger.error("create jobWeightModels: " + j.getKey() + " error!", ex); } } } return newJobThreshold; } /** * 获取资源分配线程池内部运行状态指标 * @return */ public Map<String, Object> getCurrentThreadStatus() { Map<String, Object> status = new HashMap<String, Object>(); status.put(THREAD_POOL_CORE_SISE, threadPool.getCorePoolSize()); status.put(THREAD_POOL_MAX_SIZE, threadPool.getMaximumPoolSize()); status.put(THREAD_POOL_ACTIVE_COUNT, threadPool.getActiveCount()); status.put(THREAD_POOL_COMPLETED_COUNT, threadPool.getCompletedTaskCount()); status.put(THREAD_POOL_LARGEST_SIZE, threadPool.getLargestPoolSize()); status.put(THREAD_POOL_CURRENT_SIZE, threadPool.getPoolSize()); status.put(THREAD_POOL_QUEUE_SIZE, threadPool.getQueue().size()); status.put(DEFAULT_COUNTER, defaultCounter.get()); status.put(TOTAL_COUNTER, totalCounter.get()); status.put(DEFAULT_QUEUE_COUNTER, jobQueuePool.get(DEFAULT_JOBQUEUE).size()); StringBuilder threadModel = new StringBuilder(); if (jobThreadWeightModel != null) { for (JobThreadWeightModel model : jobThreadWeightModel) { threadModel.append(model.getType()).append(":").append(model.getKey()).append(":") .append(model.getValue()).append(","); } } if (threadModel.length() > 0) { status.put(THREAD_WEIGHT_MODEL, threadModel.substring(0, threadModel.length() - 1)); } StringBuilder detailModelStatus = new StringBuilder(); Iterator<Entry<String, AtomicInteger>> entrys = counterPool.entrySet().iterator(); while (entrys.hasNext()) { Entry<String, AtomicInteger> e = entrys.next(); detailModelStatus .append(e.getKey()) .append("=") .append(new StringBuilder("private:").append(e.getValue()).append(",total:") .append(defaultCounterPool.get(e.getKey()).get()).append(",queue:") .append(jobQueuePool.get(e.getKey()).size()).toString()).append(";"); } if (detailModelStatus.length() > 0) { status.put(MODEL_SNAPSHOT, detailModelStatus.substring(0, detailModelStatus.length() - 1)); } return status; } public void stopDispatcher() { isStop = true; if (threadPool != null) threadPool.shutdownNow(); if (counterPool != null) counterPool.clear(); if (jobThreshold.getThresholdPool() != null) jobThreshold.getThresholdPool().clear(); if (jobQueuePool != null && jobQueuePool.size() > 0) { Iterator<JobQueue> values = jobQueuePool.values().iterator(); while (values.hasNext()) { JobQueue q = values.next(); q.clean(); } jobQueuePool.clear(); } ProbeNotifier.notifyThreadPoolStopped(this); } /** * 兼容普通的runnable的提交 * @param job */ public void execute(Runnable job) { if (isStop) { throw new JobRejectedException("Job Dispatcher is stopped!"); } if (job instanceof Job) execute((Job) job); else threadPool.execute(job); } /** * 检查是否有资源可用, * 注意检查过程已经有对资源数值作修改的动作,不可重复调用,避免资源泄露 * @param job * @return */ public boolean checkJobResource(Job job) { boolean hasResource = false; // 第一层做总量判断,同时锁定总资源 if (totalCounter.incrementAndGet() > this.maximumPoolSize) { totalCounter.decrementAndGet(); ProbeNotifier.notifyMaxNumberOfThreads(this, this.maximumPoolSize); return false; } String key = job.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(Job job) { boolean hasResource = checkJobResource(job); if (hasResource) { logger.debug("submit to threadpool"); threadPool.execute(job); ProbeNotifier.notifyThreadAllocated(this, job); } else { logger.debug("submit to queue"); pushJob(job); ProbeNotifier.notifyTaskQueued(this, job); } } public JobThreadWeightModel[] getJobThreadWeightModel() { return jobThreadWeightModel; } public void setJobThreadWeightModel(JobThreadWeightModel[] jobThreadWeightModelArray) { this.jobThreadWeightModel = jobThreadWeightModelArray; } // public void setJobThreadWeightModel(List<JobThreadWeightModel> jobThreadWeightModelList) { // this.jobThreadWeightModel = jobThreadWeightModelList.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 job */ public void pushJob(Job job) { JobQueue jobQueue = getJobQueue(job); if (!jobQueue.offer(job)) {// 补偿job ProbeNotifier.notifyTaskQueueOverflow(this); throw new JobRejectedException("can't submit job, queue full!"); } } /** * 根据job类型获取对应的队列 * @param job * @return */ public JobQueue getJobQueue(Job job) { JobQueue jobQueue; //采用默认的 if (job.getKey() == null || (job.getKey() != null && !jobQueuePool.containsKey(job.getKey()))) { jobQueue = jobQueuePool.get(DEFAULT_JOBQUEUE); } else { jobQueue = jobQueuePool.get(job.getKey()); } return jobQueue; } /** * 线程执行前的操作 * @param job */ public void beforeExecuteJob(Job job) { //用于统计默认线程中不同的请求消耗的线程数 if (job.getKey() != null && defaultCounterPool.containsKey(job.getKey())) { defaultCounterPool.get(job.getKey()).incrementAndGet(); } } /** * 释放线程时对于各种计数器做递减 * @param job */ public void releaseJob(Job job) { //需要增加notify的代码 String key = job.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(); } } //释放资源信号,必须放在最后 JobQueue jobQueue = getJobQueue(job); jobQueue.notifyHasResource(); ProbeNotifier.notifyThreadReleased(this, job); } public JobThreadPoolExecutor getThreadPool() { return threadPool; } public void setThreadPool(JobThreadPoolExecutor threadPool) { this.threadPool = threadPool; } }