Skip to content

Instantly share code, notes, and snippets.

@riversun
Last active August 23, 2016 10:32
Show Gist options
  • Save riversun/e1a31ca66645ca5dd6a90c0c4f66bd60 to your computer and use it in GitHub Desktop.
Save riversun/e1a31ca66645ca5dd6a90c0c4f66bd60 to your computer and use it in GitHub Desktop.
[Java]Easy to perform the tasks specified number(or infinity) of times periodically.Like a timer.
/**
* Copyright 2006-2016 Tom Misawa(riversun.org@gmail.com)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package org.riversun;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
/**
* Cyclic Task Scheduler(Like a timer class)<br>
* Perform the tasks specified number(or infinity) of times periodically<br>
* <br>
*
* @author Tom Misawa (riversun.org@gmail.com)
*/
public class CyclicTaskExecutor {
public static void main(String[] args) {
// example
long executionIntervalMillis = 1000;
int executionCount = CyclicTaskExecutor.INIFINITY;
Runnable task = new Runnable() {
private int counter = 0;
@Override
public void run() {
counter++;
System.out.println("Task counter=" + counter);
}
};
CyclicTaskExecutor cte = new CyclicTaskExecutor(task, executionCount, executionIntervalMillis);
cte.start();
waitAMoment(5000);
cte.stop();
cte.shutdownNow();
}
public static void waitAMoment(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
}
}
public static final int INIFINITY = -1;
private volatile long mInternalExecutionCount;
private final ScheduledExecutorService scheduledExecutor = Executors.newSingleThreadScheduledExecutor();
private final Runnable mTask;
private final long mExecutionIntervalMillis;
private final int mExecutionCount;
private ScheduledFuture<?> mFuture;
private boolean mInProgress = false;
private long mLastExecutionTime = 0;
private CyclicTaskListener mCallback = null;
public CyclicTaskExecutor(Runnable task, int executionCount, long executionIntervalMillis) {
this.mTask = task;
this.mInternalExecutionCount = 0;
this.mExecutionCount = executionCount;
this.mExecutionIntervalMillis = executionIntervalMillis;
}
/**
* Start performing the scheduled task
*/
public void start() {
mInternalExecutionCount = 0;
mInProgress = true;
mFuture = scheduledExecutor.scheduleAtFixedRate(new ScheduledTask(mTask), 0, mExecutionIntervalMillis, TimeUnit.MILLISECONDS);
}
/**
* Restart performing the scheduled task stopped by stop()
*/
public void restart() {
mInProgress = true;
mFuture = scheduledExecutor.scheduleAtFixedRate(new ScheduledTask(mTask), 0, mExecutionIntervalMillis, TimeUnit.MILLISECONDS);
}
/**
* Cancel current performing task<br>
* Although the current task is discarded.But scheduler itself can be
* resumed. <br>
*/
public void stop() {
mInternalExecutionCount = 0;
mInProgress = false;
if (mFuture != null) {
mFuture.cancel(true);
}
}
/**
* To cancel the performing task, and to shutdown the cycle execution
*/
public void stopAndShutdown() {
stop();
shutdownNow();
}
public void setCyclicTaskCallback(CyclicTaskListener listener) {
this.mCallback = listener;
}
public boolean isInProgress() {
return mInProgress;
}
public long getCounter() {
return mInternalExecutionCount;
}
private void stopAndShutdownSuccessfully() {
if (this.mCallback != null) {
this.mCallback.onCyclicTaskFinished(this.mTask);
}
stop();
shutdownNow();
}
private void shutdownNow() {
this.mCallback = null;
scheduledExecutor.shutdownNow();
}
/**
* Callback class
*/
public static interface CyclicTaskListener {
public void onCyclicTaskFinished(Runnable task);
}
/**
*
* Task class
*
*/
private class ScheduledTask implements Runnable {
private final Runnable mTask;
public ScheduledTask(Runnable task) {
mTask = task;
}
@Override
public void run() {
try {
if (Thread.interrupted()) {
throw new InterruptedException();
}
mInternalExecutionCount++;
final long nowTime = getNow();
final long elapsedTime = nowTime - mLastExecutionTime;
// Time that proceeds too much than the interval that set as
// default
final long fastGoingTimeMillis;
if (mExecutionIntervalMillis > elapsedTime) {
// If Executor is trying to accelerate the running speed for
// recovering the delay.
fastGoingTimeMillis = mExecutionIntervalMillis - elapsedTime;
} else {
// If Executor runs as normal
fastGoingTimeMillis = 0;
}
// Allow to become a little faster
Thread.sleep((long) ((double) fastGoingTimeMillis * (double) 0.90d));
mLastExecutionTime = nowTime;
mTask.run();
if (mInternalExecutionCount == mExecutionCount) {
stopAndShutdownSuccessfully();
}
if (Thread.interrupted()) {
throw new InterruptedException();
}
} catch (InterruptedException e) {
// ignore
}
}
}
private long getNow() {
return System.currentTimeMillis();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment