/******************************************************************************* * gMix open source project - https://svs.informatik.uni-hamburg.de/gmix/ * Copyright (C) 2014 SVS * * 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 staticContent.evaluation.loadGenerator.scheduler; import java.util.concurrent.Callable; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import staticContent.framework.config.Settings; public class ThreadPoolScheduler<E> extends Scheduler<E> { private ScheduledThreadPoolExecutor scheduler; private final static long INIT_TIME = System.nanoTime(); private long latestExecutionScheduled = Long.MIN_VALUE; private QueueEntry lastEntry = null; // @tolerance in microsec (uses microsec as nanosec would imply a higher accuracy than available) public ThreadPoolScheduler(Settings settings) { super(settings); this.scheduler = new ScheduledThreadPoolExecutor(4); } // @tolerance in microsec (uses microsec as nanosec would imply a higher accuracy than available) public ThreadPoolScheduler(Settings settings, int numberOfThreads) { super(settings); this.scheduler = new ScheduledThreadPoolExecutor(numberOfThreads); } @Override public synchronized void executeAt(long executionTime, ScheduleTarget<E> scheduleTarget, E attachment) { QueueEntry queueEntry = new QueueEntry(executionTime, scheduleTarget, attachment); if (executionTime > this.latestExecutionScheduled) { this.latestExecutionScheduled = executionTime; this.lastEntry = queueEntry; } long delay = executionTime - now(); if (delay < 0) delay = 0; scheduler.schedule(queueEntry, delay, TimeUnit.NANOSECONDS); } @Override public synchronized void executeIn(long delayInNanoSec, ScheduleTarget<E> scheduleTarget, E attachment) { if (delayInNanoSec < 0) delayInNanoSec = 0; long executionTime = now() + delayInNanoSec; QueueEntry queueEntry = new QueueEntry(executionTime, scheduleTarget, attachment); if (executionTime > this.latestExecutionScheduled) { this.latestExecutionScheduled = executionTime; this.lastEntry = queueEntry; } scheduler.schedule(queueEntry, delayInNanoSec, TimeUnit.NANOSECONDS); } @Override public long now() { return System.nanoTime() - INIT_TIME; } @Override public void notifyOnOutputOfLast(ScheduleTarget<E> notifyTarget) { this.lastEntry.notifyTarget = notifyTarget; } @Override public void shutdown() { this.scheduler.shutdownNow(); } private class QueueEntry implements Callable<E> { long executionTime; ScheduleTarget<E> scheduleTarget; E attachment; ScheduleTarget<E> notifyTarget; private QueueEntry(long executionTime, ScheduleTarget<E> scheduleTarget, E attachment) { this.executionTime = executionTime; this.scheduleTarget = scheduleTarget; this.attachment = attachment; } @Override public E call() throws Exception { warnIfDelayed(now() - this.executionTime); if (this.notifyTarget != null) this.notifyTarget.execute(this.attachment); this.scheduleTarget.execute(this.attachment); return this.attachment; } } }