package org.googlecode.threadpool; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.Iterator; import java.util.Map.Entry; import java.util.concurrent.BlockingQueue; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.googlecode.threadpool.util.NamedThreadFactory; 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; /** * @author zhongfeng * */ public class TaskCentralExecutor extends ThreadPoolExecutor { private static final Logger LOG = LoggerFactory .getLogger(TaskCentralExecutor.class); private final TimeoutMonitor timeoutMonitor = TimeoutMonitor.getInstance();; private final LoadingCache<String, BufferQueue> bufferQueueRepo; /** * */ private final CopyOnWriteArrayList<BufferQueue> bufferQueueMirror; private final TaskQuotaAllocator taskQuotaAllocator; private final PoolConfig poolConfig; private static TaskCentralExecutor INSTANCE; private final ExecutorService exec = Executors .newSingleThreadExecutor(new NamedThreadFactory( "Task-Notify-Resource-Thread", false)); private TaskCentralExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, PoolConfig poolConfig) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue); this.poolConfig = poolConfig; this.taskQuotaAllocator = TaskQuotaAllocator.getInstance(poolConfig); this.bufferQueueMirror = new CopyOnWriteArrayList<BufferQueue>(); this.bufferQueueRepo = initBufferQueueCache(poolConfig, this.bufferQueueMirror); } private LoadingCache<String, BufferQueue> initBufferQueueCache( PoolConfig poolConfig, CopyOnWriteArrayList<BufferQueue> bufferQueueList) { return CacheBuilder.newBuilder().build( new BufferQueueCacheLoader(poolConfig, bufferQueueList, this)); } @Override protected void afterExecute(Runnable r, Throwable t) { RunnableTask task = null; if (r instanceof RunnableTask) { task = (RunnableTask) r; } else if (r instanceof FutureTaskDelay) { task = ((FutureTaskDelay) r).getTask(); } if (task != null) { LOG.debug("CentralExecutor-AfterExecute release:{}", task); releaseTask(task); } else { LOG.warn("Error. r is : {}", r); } } @Override protected void beforeExecute(Thread t, Runnable r) { LOG.debug("CentralExecutor-BeforeExecute", r); } public void runTask(RunnableTask runnableTask) { if (runnableTask.getTimeout() > 0) { FutureTaskDelay fTask = timeoutMonitor .addTaskTimeoutMonitor(runnableTask); LOG.debug("Run task : {} at : {}", runnableTask, new Date()); execute(fTask); } else { LOG.debug("Run task : {} at : {}", runnableTask, new Date()); execute(runnableTask); } } /** * @param runnableTask * @return */ public boolean acquireResource(RunnableTask runnableTask) { return taskQuotaAllocator.acquire(runnableTask); } /** * @param runnableTask * @return */ public void releaseResource(RunnableTask runnableTask) { taskQuotaAllocator.release(runnableTask); } /** * 提交任务,存在一个优先级问题 如果队列不为空,提交执行的任务会被放入队列中 */ public void submitTask(RunnableTask runnableTask) { LOG.debug("Submit task : {} , at : {}", runnableTask, new Date()); if (hasWaitTask(runnableTask)) { LOG.debug("HasWaitTask.Put in Buffer Q. {}", runnableTask); putQueue(runnableTask); } else { if (acquireResource(runnableTask)) { runTask(runnableTask); } else { LOG.debug("NoResource. Put in Buffer Q. {}", runnableTask); putQueue(runnableTask); } } } /** * @param runnableTask */ private void releaseTask(RunnableTask runnableTask) { LOG.debug("Release task : {}", runnableTask); // 已完成的Task,取消超时监控 timeoutMonitor.cancelTaskTimeoutMonitor(runnableTask); // 资源释放,计数器增加 releaseResource(runnableTask); // 通知该服务有可用资源 notifyHasResource(runnableTask); } public synchronized static TaskCentralExecutor getInstance( PoolConfig poolConfig) { if (INSTANCE == null) { INSTANCE = new TaskCentralExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), poolConfig); } return INSTANCE; } public boolean putQueue(RunnableTask task) { boolean flag = getTaskQueue(task).addTask(task); if (!flag) { LOG.warn("Q is full. Discard"); } return flag; } public boolean hasWaitTask(RunnableTask task) { return (!getTaskQueue(task).isEmpty()); } public void notifyHasResource(final RunnableTask task) { getTaskQueue(task).notifyHasResource(); if (!task.isReserve()) { exec.submit(new Runnable() { @Override public void run() { // 需要改进,有一点性能问题 Collections.shuffle(bufferQueueMirror); for (BufferQueue taskQueue : bufferQueueMirror) taskQueue.notifyHasResource(); } }); } } /** * @param task */ private BufferQueue getTaskQueue(RunnableTask task) { BufferQueue queue = null; try { queue = getBufferQueueRepo().get(task.getTaskKey()); } catch (ExecutionException e) { // LOG.error("Get Queue Error", e); } return queue; } public LoadingCache<String, BufferQueue> getBufferQueueRepo() { return bufferQueueRepo; } public Collection<BufferQueue> getAllBufferQueue() { return getBufferQueueRepo().asMap().values(); } public TimeoutMonitor getTimeoutMonitor() { return timeoutMonitor; } public CopyOnWriteArrayList<BufferQueue> getBufferQueueMirror() { return bufferQueueMirror; } public TaskQuotaAllocator getTaskQuotaAllocator() { return taskQuotaAllocator; } public PoolConfig getPoolConfig() { return poolConfig; } public void shutdown() { Iterator<Entry<String, BufferQueue>> iter = getBufferQueueRepo() .asMap().entrySet().iterator(); while (iter.hasNext()) { iter.next().getValue().stop(); } getBufferQueueRepo().invalidateAll(); } public final static class BufferQueueCacheLoader extends CacheLoader<String, BufferQueue> { private PoolConfig poolConfig; private CopyOnWriteArrayList<BufferQueue> bufferQueueMirror; private TaskCentralExecutor centralExecutor; /** * @param poolConfig */ public BufferQueueCacheLoader(PoolConfig poolConfig, CopyOnWriteArrayList<BufferQueue> bufferQueueMirror, TaskCentralExecutor centralExecutor) { this.poolConfig = poolConfig; this.bufferQueueMirror = bufferQueueMirror; this.centralExecutor = centralExecutor; } @Override public BufferQueue load(String key) throws Exception { BufferQueue queue = BufferQueue.newInstance(key, poolConfig .getTaskConfig(key).getBufferSize()); bufferQueueMirror.add(queue); queue.startQueueTaskSubmit(centralExecutor); return queue; } } }