package com.griddynamics.jagger.engine.e1.process; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.concurrent.*; /** * Loop scheduler that can execute one task with given period. * If you add new task - previous will be canceled. * You can change period of process at runtime. */ public class PeriodSingleTaskScheduler { private ScheduledExecutorService loopExecutor; private ExecutorService taskExecutor; /** * Last started schedule process, saved to be able to stop it */ private ScheduledFuture lastStartedLoopProcess = null; private static final int DEFAULT_CORE_POOL_SIZE = 2; /** * Last started configuration */ private volatile Configuration currentConfiguration; Logger log = LoggerFactory.getLogger(PeriodSingleTaskScheduler.class); public PeriodSingleTaskScheduler() { loopExecutor = Executors.newScheduledThreadPool(DEFAULT_CORE_POOL_SIZE); taskExecutor = Executors.newFixedThreadPool(5); } /** * Schedule command at fixed rate. * Cancel previously started process. * * @param command command to be executed every period * @param initialDelay initialDelay before executing command * @param period period * @param unit time unit for period, initialDelay */ public synchronized void scheduleAtFixedRate(final Runnable command, long initialDelay, long period, TimeUnit unit) { Configuration newConfiguration = new Configuration(command, initialDelay, period, unit); if (!newConfiguration.equals(currentConfiguration)) { log.debug("Schedule new task {}", newConfiguration); currentConfiguration = newConfiguration; // cancel task if running if (lastStartedLoopProcess != null) { // stop previous loop process, but do not interrupt lastStartedLoopProcess.cancel(false); } lastStartedLoopProcess = loopExecutor.scheduleAtFixedRate(new Runnable() { @Override public void run() { taskExecutor.submit(command); } }, initialDelay, period, unit); } } /** * Shutdown scheduler */ public synchronized void shutdown() { loopExecutor.shutdownNow(); taskExecutor.shutdownNow(); } /** * Disable Task */ public synchronized void clear() { if (lastStartedLoopProcess != null) { lastStartedLoopProcess.cancel(false); } currentConfiguration = null; } /** * Represents current configuration of loop process */ private class Configuration { private final Runnable command; private final long initialDelay; private final long period; private final TimeUnit unit; public Configuration(Runnable command, long delay, long period, TimeUnit unit) { this.command = command; this.initialDelay = delay; this.period = period; this.unit = unit; } public Runnable getCommand() { return command; } public long getInitialDelay() { return initialDelay; } public long getPeriod() { return period; } public TimeUnit getUnit() { return unit; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Configuration that = (Configuration) o; if (initialDelay != that.initialDelay) return false; if (period != that.period) return false; if (command != null ? !command.equals(that.command) : that.command != null) return false; if (unit != that.unit) return false; return true; } } }