package phoenix.util.pool; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.PriorityBlockingQueue; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class CentralExecutor implements Executor { private static final Logger LOGGER = LoggerFactory.getLogger(CentralExecutor.class); private static final String CLASS_NAME = CentralExecutor.class.getSimpleName(); private final ExecutorService service; private final Policy policy; private final Map<Class<? extends Runnable>, Submitter> quotas; private final int threadSize; private int reserved; public CentralExecutor(final int threadSize, Policy policy) { this.threadSize = threadSize; this.policy = policy; this.service = Executors.newFixedThreadPool(threadSize, new DebugableThreadFactory(CLASS_NAME)); this.quotas = new ConcurrentHashMap<Class<? extends Runnable>, Submitter>(); } public CentralExecutor(int threadSize) { this(threadSize, Policy.PESSIMISM); } /** @see ExecutorService#shutdownNow() */ public List<Runnable> shutdownNow() { return service.shutdownNow(); } /** @see ExecutorService#shutdown() */ public void shutdown() { service.shutdown(); } /** @see ExecutorService#isShutdown() */ public boolean isShutdown() { return service.isShutdown(); } /** @see ExecutorService#isTerminated() */ public boolean isTerminated() { return service.isTerminated(); } /** @see ExecutorService#awaitTermination(long, java.util.concurrent.TimeUnit) */ public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { return service.awaitTermination(timeout, unit); } @Override public void execute(Runnable task) { final Submitter submitter = quotas.get(task.getClass()); if (submitter != null) submitter.submit(task, this); else policy.defaultSubmitter().submit(task, this); } /** @return 预留配额. */ public static Quota reserve(int value) { return new Quota(value); } /** @return 弹性配额. */ public static Quota elastic(int value) { return new Quota(value); } /** @return 零配额. */ public static Quota nil() { return new Quota(0); } /** * 设定taskClass的保留和限制配额. * * @param taskClass * @param reserve * @param elastic * * @throws IllegalArgumentException */ public void quota(Class<? extends Runnable> taskClass, Quota reserve, Quota elastic) { synchronized (this) { if (reserve.value > threadSize - reserved) throw new IllegalArgumentException("No resource for reserve"); reserved += reserve.value; } quotas.put(taskClass, policy.submitter(reserve, elastic)); } private synchronized boolean hasUnreserved() { return threadSize > reserved; } /** {@link Quota} */ private final static class Quota { private final AtomicInteger state; private final int value; private Quota(int value) { if (value < 0) throw new IllegalArgumentException("Quota should not less than 0."); this.value = value; this.state = new AtomicInteger(value); } /** @return 当前剩余配额. */ public int state() { return state.get(); } /** * 占据一个配额. * * @return false 表示预留的配额以用完, 反之为true. */ public boolean acquire() { if (state() == 0) return false; if (state.decrementAndGet() >= 0) return true; state.incrementAndGet(); return false; } /** * 释放一个配额. * * @return false 表示无效的释放, 正常情况下不应出现, 反之为true. */ public boolean release() { if (state() == value) return false; if (state.incrementAndGet() <= value) return true; state.decrementAndGet(); return false; } } /** {@link Policy} */ public static enum Policy { /** 乐观策略, 在存在为分配的配额情况下, 一旦出现闲置线程, 允许任务抢占, 抢占的优先级由提交的先后顺序决定. */ OPTIMISM { /** 未定义配额的任务将直接进入等待队列, 但优先级低于所有定义了配额的任务. */ private final Submitter defaultSubmitter = new Submitter() { @Override public void submit(Runnable task, CentralExecutor executor) { enqueue(new ComparableTask(task, Integer.MAX_VALUE)); } }; @Override Submitter defaultSubmitter() { return defaultSubmitter; } @Override Submitter submitter(final Quota reserve, final Quota elastic) { return new Submitter() { @Override public void submit(final Runnable task, CentralExecutor executor) { if (reserve.acquire()) doSubmit(task, executor, reserve); // 若存在为分配的预留配额, 则弹性配额进行争抢 else if (executor.hasUnreserved() && elastic.acquire()) doSubmit(task, executor, elastic); // 同悲观策略进入等待队列 else enqueue(new ComparableTask(task, reserve.value)); } }; } }, /** 悲观策略, 在所有线程都被预留的情况下, 即使当前预留之外的线程是空闲, 也不会被抢占, 即Elastic的设定将被忽略. */ PESSIMISM { private final Submitter defaultSubmitter = new Submitter() { @Override public void submit(Runnable task, CentralExecutor executor) { throw new RejectedExecutionException("Unquotaed task can not be executed in pessimism."); } }; @Override Submitter defaultSubmitter() { return defaultSubmitter; } @Override Submitter submitter(final Quota reserve, final Quota elastic) { if (reserve.value == 0) throw new IllegalArgumentException("None-reserve task will never be executed in pessimism."); return new Submitter() { @Override public void submit(final Runnable task, CentralExecutor executor) { if (reserve.acquire()) doSubmit(task, executor, reserve); // 耗尽预留配额后, 进入等待队列, 按预留额度大小排优先级, 大者优先. else enqueue(new ComparableTask(task, reserve.value)); } }; } }; /** 优先级等待队列. */ private final PriorityBlockingQueue<ComparableTask> queue = new PriorityBlockingQueue<ComparableTask>(); abstract Submitter submitter(Quota reserve, Quota elastic); abstract Submitter defaultSubmitter(); /** 将任务入等待队列. */ void enqueue(ComparableTask task) { queue.put(task); LOGGER.debug("Enqueue {}", task.original); } /** 将任务出列重新提交给执行器. */ void dequeueTo(CentralExecutor executor) { try { final Runnable task = queue.take().original; LOGGER.debug("Dequeue {}", task); executor.execute(task); } catch (InterruptedException e) { Thread.currentThread().interrupt(); LOGGER.debug("Dequeue has been interrupted ", e); } } void doSubmit(Runnable task, CentralExecutor executor, Quota quota) { executor.service.execute(new Decorator(task, quota, executor)); } /** {@link ComparableTask} */ static class ComparableTask implements Comparable<ComparableTask> { final Runnable original; private final int quota; public ComparableTask(Runnable task, int quota) { this.original = task; this.quota = quota; } @Override public int compareTo(ComparableTask o) { return -(quota - o.quota); } } /** {@link Decorator} */ class Decorator implements Runnable { private final Runnable task; private final Quota quota; private final CentralExecutor executor; public Decorator(Runnable task, Quota quota, CentralExecutor executor) { this.task = task; this.quota = quota; this.executor = executor; } @Override public void run() { try { task.run(); } catch (Throwable t) { LOGGER.error("Unexpected Interruption cause by", t); } finally { quota.release(); dequeueTo(executor); } } } } /** {@link Submitter} */ private static interface Submitter { void submit(Runnable task, CentralExecutor executor); } }