package ilarkesto.concurrent; import ilarkesto.base.Utl; import ilarkesto.core.logging.Log; import ilarkesto.di.Context; import java.util.HashSet; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class TaskManager { private static final Log LOG = Log.get(TaskManager.class); private Set<ATask> runningTasks = new HashSet<ATask>(); private Set<ATask> scheduledTasks = new HashSet<ATask>(); private Set<TaskRunner> taskRunners = new HashSet<TaskRunner>(); private ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5, new DeamonThreadFactory()); private ExecutorService executorService = Executors.newCachedThreadPool(new DeamonThreadFactory()); private boolean shutdownInProgress; public void waitForRunningTasks() { waitForRunningTasks(Long.MAX_VALUE); } public void waitForRunningTasks(long maxWaitTime) { long now = System.currentTimeMillis(); long tryUntilTime = now + maxWaitTime; if (tryUntilTime < now) tryUntilTime = Long.MAX_VALUE; Set<ATask> tasks; while ((!(tasks = getRunningTasks()).isEmpty()) && System.currentTimeMillis() < tryUntilTime) { LOG.info("Waiting for running tasks:", tasks); synchronized (this) { try { this.wait(1000); } catch (InterruptedException ex) {} } } } public Set<ATask> getRunningTasks() { synchronized (runningTasks) { return new HashSet<ATask>(runningTasks); } } public void abortAllRunningTasks() { for (ATask task : getRunningTasks()) { LOG.info("Aborting task:", task); task.abort(); } } public void shutdown(long waitUntilKill) { shutdownInProgress = true; unscheduleAllTasks(); scheduledExecutorService.shutdownNow(); abortAllRunningTasks(); waitForRunningTasks(waitUntilKill); executorService.shutdownNow(); } public Set<ATask> getScheduledTasks() { return new HashSet<ATask>(scheduledTasks); } public void start(ATask task) { if (shutdownInProgress) { LOG.info("Task execution prevented, cause shutdown in progress:", task); return; } TaskRunner runner = new TaskRunner(task, false, Context.get()); executorService.execute(runner); } public void scheduleWithFixedDelay(ATask task, long delay) { scheduleWithFixedDelay(task, delay, delay); } public void scheduleWithFixedDelay(ATask task, long initialDelay, long delay) { scheduledTasks.add(task); scheduledExecutorService.scheduleWithFixedDelay(new TaskRunner(task, true, Context.get()), initialDelay, delay, TimeUnit.MILLISECONDS); LOG.info("Scheduled task:", task); } public boolean unschedule(ATask task) { return scheduledTasks.remove(task); } public void unscheduleAllTasks() { if (!scheduledTasks.isEmpty()) LOG.info("Removing scheduled tasks:", scheduledTasks); scheduledTasks.clear(); } class TaskRunner implements Runnable { private ATask task; private boolean repeating; private Context parentContext; public TaskRunner(ATask task, boolean repeating, Context parentContext) { this.task = task; this.repeating = repeating; this.parentContext = parentContext; } public void run() { synchronized (taskRunners) { taskRunners.add(this); } Context context = parentContext.createSubContext("task:" + task.toString()); // Thread.currentThread().setName(task.toString()); synchronized (runningTasks) { runningTasks.add(task); } // LOG.debug("Task started:", task); try { task.run(); } catch (Throwable ex) { if (shutdownInProgress && Utl.getRootCause(ex) instanceof InterruptedException) { LOG.info("Task interrupted while shutdown:", Utl.toStringWithType(task)); } else { LOG.error(ex); } } // LOG.debug("Task finished:", task); synchronized (runningTasks) { runningTasks.remove(task); } if (repeating) task.reset(); context.destroy(); synchronized (TaskManager.this) { TaskManager.this.notifyAll(); } synchronized (taskRunners) { taskRunners.remove(this); } } } }