package org.googlecode.threadpool; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutionException; import org.googlecode.threadpool.PoolConfig.TaskConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; /** * * 先构建所有的Reserve方式的quota,满足条件:所有的Reserve Quota总和 < maximumPoolSize; * 如果剩余的sharedPoolSize小于默认最小值,则分配失败; * * * @author zhongfeng * */ class TaskQuotaAllocator { private static final Logger LOG = LoggerFactory .getLogger(TaskQuotaAllocator.class); private static TaskQuotaAllocator INSTANCE; /** * */ private LoadingCache<String, TaskQuota> quotaCache; /** * 共享配额 */ private Quota sharedTaskQuota; /** * 线程池总大小 */ private int maximumPoolSize; /** * PoolConfig保持了全局的配置,TaskQuotaAllocator构建从PoolConfig开始 */ private TaskQuotaAllocator(PoolConfig poolConfig) { this.quotaCache = CacheBuilder.newBuilder().build( new TaskQuotaCacheLoader(poolConfig)); this.maximumPoolSize = poolConfig.getMaximumPoolSize(); // 构建sharedTaskQuota this.sharedTaskQuota = buildSharedTaskQuota(poolConfig); } /** * * @return totalLeaveYHQuota 分配出去的独占Quota总量 * */ private int buildReservePolicyTaskQuota(PoolConfig poolConfig) { int totalLeaveQuota = 0; for (TaskConfig taskCfg : poolConfig.getAllTaskConfig()) { TaskQuota taskQuota = new TaskQuota(taskCfg.getTaskKey(), taskCfg .getReserve(), taskCfg.getElastic()); totalLeaveQuota += taskQuota.getReserveQuota().getValue(); // 校验totalLeaveQuota不能大于maximumPoolSize if (totalLeaveQuota > getMaximumPoolSize()) throw new IllegalArgumentException("TotalLeaveQuota: " + totalLeaveQuota + " is greater than maximumPoolSize:" + getMaximumPoolSize()); quotaCache.put(taskQuota.getTaskKey(), taskQuota); } return totalLeaveQuota; } private Quota buildSharedTaskQuota(PoolConfig poolConfig) { int totalLeaveQuota = buildReservePolicyTaskQuota(poolConfig); // sharedPoolSize大小等于maximumPoolSize减去所有leave模式占用的 int sharedPoolSize = (poolConfig.getMaximumPoolSize() - totalLeaveQuota); // 如果公用池小于minAvailableSharedPoolSize,初始化报错 if (sharedPoolSize < poolConfig.getMinAvailableSharedPoolSize()) throw new IllegalArgumentException("Current SharedPoolSize is: " + sharedPoolSize + " less than minAvailableSharedPoolSize : " + poolConfig.getMinAvailableSharedPoolSize()); return new Quota(sharedPoolSize); } public boolean acquire(RunnableTask runnableTask) { // 不会取到NULL TaskQuota quota = getTaskQuota(runnableTask); LOG.debug("Acquire currentQuota : {}", quota); List<Quota> taskCurrrentUsedQuota = new ArrayList<Quota>(); // 优先使用独占资源 if (quota.getReserveQuota().acquire()) { LOG.debug("Use Reserve Resource. Success Quota is : {}", quota); taskCurrrentUsedQuota.add(quota.getReserveQuota()); runnableTask.setCurrentUsedQuota(taskCurrrentUsedQuota); runnableTask.setReserve(true); return true; } // 独占资源用完后,尝试竞争共享资源 boolean limitQuotaAC = quota.getElasticQuota().acquire(); if (!limitQuotaAC) { LOG.debug("GetElasticQuota Fail. Quota is : {}", quota); return false; } boolean flag = false; boolean sharedTaskQuotaAc = sharedTaskQuota.acquire(); // limitQuotaAC && sharedTaskQuotaAc 同时获取成功 flag = true if (sharedTaskQuotaAc) { LOG.debug("Use Shared Resource. Success Quota is : {}", quota); taskCurrrentUsedQuota.add(quota.getElasticQuota()); taskCurrrentUsedQuota.add(sharedTaskQuota); runnableTask.setCurrentUsedQuota(taskCurrrentUsedQuota); runnableTask.setReserve(false); flag = true; } else { LOG.debug("SharedTaskQuota Fail. Shared Quota is : {}", sharedTaskQuota.state()); if (limitQuotaAC) { quota.getElasticQuota().release(); } } return flag; } /** * @param runnableTask * @param quota * @return */ private TaskQuota getTaskQuota(RunnableTask runnableTask) { return getTaskQuota(runnableTask.getTaskKey()); } public TaskQuota getTaskQuota(String taskKey) { try { return quotaCache.get(taskKey); } catch (ExecutionException e) { // 不会发生 throw new RuntimeException(e); } } public void release(RunnableTask runnableTask) { for (Quota quota : runnableTask.getCurrentUsedQuota()) quota.release(); } public synchronized static TaskQuotaAllocator getInstance( PoolConfig poolConfig) { if (INSTANCE == null) { INSTANCE = new TaskQuotaAllocator(poolConfig); } return INSTANCE; } public int getMaximumPoolSize() { return maximumPoolSize; } public final static class TaskQuotaCacheLoader extends CacheLoader<String, TaskQuota> { private PoolConfig poolConfig; /** * @param poolConfig */ private TaskQuotaCacheLoader(PoolConfig poolConfig) { this.poolConfig = poolConfig; } @Override public TaskQuota load(String key) throws Exception { // 如果没有配置key的quota,则使用默认的设置;无限抢占共用资源 TaskConfig taskConfig = poolConfig.getTaskConfig(key); return new TaskQuota(taskConfig.getTaskKey(), taskConfig .getReserve(), taskConfig.getElastic()); } } }