PeriodicTask.java
package eu.javaexperience.scheduler.periodic;
import java.util.concurrent.atomic.AtomicReference;
import eu.javaexperience.Global.LazySingletons;
import eu.javaexperience.asserts.AssertArgument;
import eu.javaexperience.interfaces.simple.SimpleCall;
public class PeriodicTask
{
public class PendingTask
{
protected boolean mayRun = true;
public final long runOnTime;
protected PendingTask(long runOnTime)
{
this.runOnTime = runOnTime;
}
public SimpleCall getCallable()
{
return call;
}
}
protected AtomicReference<PendingTask> nextTask = new AtomicReference<>();
protected volatile boolean run = false;
protected int interval;
protected final SimpleCall call;
public PeriodicTask(SimpleCall call,int milisec)
{
AssertArgument.assertNotNull(this.call = call, "call");
AssertArgument.assertGreaterThan(this.interval = milisec, 0, "interval in milisec");
}
public boolean isRunning()
{
return run;
}
public void start()
{
if(run)
throw new IllegalStateException("Periodic task is already started");
PendingTask task = nextTask.get();
if(task != null)
task.mayRun = false;
run = true;
enqueueNew();
}
protected void enqueueNew()
{
enqueueNewWithInterval(interval);
}
protected void enqueueNewWithInterval(int interval)
{
final PendingTask ptask = new PendingTask(System.currentTimeMillis()+interval);
nextTask.set(ptask);
LazySingletons.timeoutJobPool().putTimoutJob(interval, new SimpleCall()
{
@Override
public void call()
{
if(ptask.mayRun)
{
try
{
ptask.getCallable().call();
}
catch(Exception e)
{
e.printStackTrace();
}
enqueueNew();
}
}
});
}
public void stop()
{
if(!run)
throw new IllegalStateException("Periodic task is already stopped");
run = false;
PendingTask task = nextTask.get();
if(task != null)
task.mayRun = false;
}
/**
* Ha rövidebb időt adunk meg mint az előző és már letelt az előző ütemezés + interval
* akkor most azonnal (de másik szálon) lefuttatjuk és utána az új intervallum lesz érvényben.
*
* Ha hosszabb időt adunk meg, akkor még a következőt feladatot is tovább várakoztatjuk.
*
* Minden beavatkozás nélkül visszatér ha a milisec < 0 vagy ugyanaz mint amennyi most be van állítva.
* */
public void adjustInterval(int milisec)
{
if(milisec < 0 || interval == milisec)
return;
PendingTask task = nextTask.get();
if(task != null)
{
long commandTime = task.runOnTime - interval;
interval = milisec;
if(commandTime <= System.currentTimeMillis())
{
LazySingletons.timeoutJobPool().putTimoutJob(0, new SimpleCall()
{
@Override
public void call()
{
call.call();
}
});
enqueueNew();
}
else
{
long inter = (commandTime + milisec) - System.currentTimeMillis();
enqueueNewWithInterval((int)(inter < 0? 0:inter));
}
}
else if(run)
enqueueNew();
}
}