/* * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program. If not, see <http://www.gnu.org/licenses/>. */ package com.vethrfolnir.services.threads; import java.util.ArrayList; import java.util.List; import java.util.concurrent.*; import java.util.logging.Level; import java.util.logging.Logger; import corvus.corax.Corax; import corvus.corax.config.CorvusConfig; import corvus.corax.inject.Inject; /** * @author Seth */ public final class CorvusThreadPool { private static final long MAX_DELAY = TimeUnit.NANOSECONDS.toMillis(Long.MAX_VALUE - System.nanoTime()) / 2; private static final Logger _log = Logger.getLogger(CorvusThreadPool.class.getName()); private ScheduledThreadPoolExecutor _scheduleExecutor; private ThreadPoolExecutor _imidiatExecutor; private ThreadPoolExecutor _longExecutor; @Inject public void load() { try { CorvusConfig config = Corax.config(); int scheduleCoreSize = config.getProperty("CoraxTScheduleCoreSize", 10); int coreSize = config.getProperty("CoraxTImidiatCoreSize", Runtime.getRuntime().availableProcessors()); int poolSize = config.getProperty("CoraxTImidiatPoolSize", 10); int longCoreSize = config.getProperty("CoraxTLongCoreSize", 0); _scheduleExecutor = new ScheduledThreadPoolExecutor(scheduleCoreSize); _imidiatExecutor = new ThreadPoolExecutor(coreSize, poolSize, 5L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); _longExecutor = new ThreadPoolExecutor(longCoreSize, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); scheduleAtFixedRate(new PurgeTask(_scheduleExecutor, _imidiatExecutor, _longExecutor), 60000, 60000); } catch (Exception e) { _log.log(Level.SEVERE, "Cannot creat thread pool manager!", e); } } private final long validate(long delay) { return Math.max(0, Math.min(MAX_DELAY, delay)); } public final ScheduledFuture<?> scheduleAtFixedRate(Runnable r, long delay, long period) { delay = validate(delay); period = validate(period); return _scheduleExecutor.scheduleAtFixedRate(new ExecutionWrapper(r), delay, period, TimeUnit.MILLISECONDS); } /** * @param callable * @param later * @param milliseconds * @return */ public ScheduledFuture<?> schedule(Runnable callable, long later) { return _scheduleExecutor.schedule(callable, later, TimeUnit.MILLISECONDS); } public final void execute(Runnable r) { _imidiatExecutor.execute(new ExecutionWrapper(r)); } public final void executeLongRunning(Runnable r) { _longExecutor.execute(new ExecutionWrapper(r)); } public final Future<?> submit(Runnable r) { return _imidiatExecutor.submit(new ExecutionWrapper(r)); } public final Future<?> submitLongRunning(Runnable r) { return _longExecutor.submit(new ExecutionWrapper(r)); } public List<String> getStats() { List<String> list = new ArrayList<String>(); list.add(""); list.add("Scheduled pool:"); list.add("================================================="); list.add("\tgetActiveCount: ...... " + _scheduleExecutor.getActiveCount()); list.add("\tgetCorePoolSize: ..... " + _scheduleExecutor.getCorePoolSize()); list.add("\tgetPoolSize: ......... " + _scheduleExecutor.getPoolSize()); list.add("\tgetLargestPoolSize: .. " + _scheduleExecutor.getLargestPoolSize()); list.add("\tgetMaximumPoolSize: .. " + _scheduleExecutor.getMaximumPoolSize()); list.add("\tgetCompletedTaskCount: " + _scheduleExecutor.getCompletedTaskCount()); list.add("\tgetQueuedTaskCount: .. " + _scheduleExecutor.getQueue().size()); list.add("\tgetTaskCount: ........ " + _scheduleExecutor.getTaskCount()); list.add(""); list.add("Instant pool:"); list.add("================================================="); list.add("\tgetActiveCount: ...... " + _imidiatExecutor.getActiveCount()); list.add("\tgetCorePoolSize: ..... " + _imidiatExecutor.getCorePoolSize()); list.add("\tgetPoolSize: ......... " + _imidiatExecutor.getPoolSize()); list.add("\tgetLargestPoolSize: .. " + _imidiatExecutor.getLargestPoolSize()); list.add("\tgetMaximumPoolSize: .. " + _imidiatExecutor.getMaximumPoolSize()); list.add("\tgetCompletedTaskCount: " + _imidiatExecutor.getCompletedTaskCount()); list.add("\tgetQueuedTaskCount: .. " + _imidiatExecutor.getQueue().size()); list.add("\tgetTaskCount: ........ " + _imidiatExecutor.getTaskCount()); list.add(""); list.add("Long running pool:"); list.add("================================================="); list.add("\tgetActiveCount: ...... " + _longExecutor.getActiveCount()); list.add("\tgetCorePoolSize: ..... " + _longExecutor.getCorePoolSize()); list.add("\tgetPoolSize: ......... " + _longExecutor.getPoolSize()); list.add("\tgetLargestPoolSize: .. " + _longExecutor.getLargestPoolSize()); list.add("\tgetMaximumPoolSize: .. " + _longExecutor.getMaximumPoolSize()); list.add("\tgetCompletedTaskCount: " + _longExecutor.getCompletedTaskCount()); list.add("\tgetQueuedTaskCount: .. " + _longExecutor.getQueue().size()); list.add("\tgetTaskCount: ........ " + _longExecutor.getTaskCount()); list.add(""); return list; } public void shutdown() { final long begin = System.currentTimeMillis(); _log.info("ThreadPoolManager: Shutting down."); _log.info("\t... executing " + getTaskCount(_scheduleExecutor) + " scheduled tasks."); _log.info("\t... executing " + getTaskCount(_imidiatExecutor) + " instant tasks."); _log.info("\t... executing " + getTaskCount(_longExecutor) + " long running tasks."); _scheduleExecutor.shutdown(); _imidiatExecutor.shutdown(); _longExecutor.shutdown(); boolean success = false; try { success |= awaitTermination(5000); _scheduleExecutor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false); _scheduleExecutor.setContinueExistingPeriodicTasksAfterShutdownPolicy(false); success |= awaitTermination(10000); } catch(InterruptedException e) { e.printStackTrace(); } _log.info("\t... success: " + success + " in " + (System.currentTimeMillis() - begin) + " msec."); _log.info("\t... " + getTaskCount(_scheduleExecutor) + " scheduled tasks left."); _log.info("\t... " + getTaskCount(_imidiatExecutor) + " instant tasks left."); _log.info("\t... " + getTaskCount(_longExecutor) + " long running tasks left."); } private int getTaskCount(ThreadPoolExecutor tp) { return tp.getQueue().size() + tp.getActiveCount(); } private boolean awaitTermination(long timeoutInMillisec) throws InterruptedException { final long begin = System.currentTimeMillis(); while(System.currentTimeMillis() - begin < timeoutInMillisec) { if(!_scheduleExecutor.awaitTermination(10, TimeUnit.MILLISECONDS) && _scheduleExecutor.getActiveCount() > 0) continue; if(!_imidiatExecutor.awaitTermination(10, TimeUnit.MILLISECONDS) && _imidiatExecutor.getActiveCount() > 0) continue; if(!_longExecutor.awaitTermination(10, TimeUnit.MILLISECONDS) && _longExecutor.getActiveCount() > 0) continue; return true; } return false; } /** * @return the imidiatExecutor */ public ThreadPoolExecutor getImidiatExecutor() { return _imidiatExecutor; } /** * @return the longExecutor */ public ThreadPoolExecutor getLongExecutor() { return _longExecutor; } /** * @return the scheduleExecutor */ public ScheduledThreadPoolExecutor getScheduleExecutor() { return _scheduleExecutor; } }