问题
I am working on a program that will read data from a data source, and publish that data as it is read. I have a reader and a writer, the reader spawns several threads to read all the data it needs to read, puts the data into a queue, and the writer reads the data from the queue an publishes it.
I have a controller for my readers and a controller for my writers. The controllers implement the Callable
interface, but could implement the Runnable
interface as my call return is Void
.
I want to use an executor to run the two controllers. The reader controller will need to be invoked every X minutes (and X is greater than the time it takes the controller to run).
Right now, I am creating a list of Callables
, sending them to an ExecutorService that is:
List<Future<Void>> futures = ExecutorService es = new Executors.newFixedThreadPoll(2);
for(Future<Void> future: futures) {
try {
future.get();
} catch (Exception e) {
// log the error
}
}
How can I turn this into a scheduling executor that runs the callables every 30 minutes (or more precisely, 30 minutes after the last job ran)?
回答1:
Okay you can do it several ways . but if performance is important you could handle these things in you own thread like this :
public class TaskTimer extends Thread {
private java.util.concurrent.LinkedBlockingQueue<Runnable> taskQueue;
private int timeToWait;
private Long lastTime = -1l;
public TaskTimer(int time)
{
if(time<0)
throw new IllegalStateException("time can not negative");
timeToWait = time;
taskQueue = new java.util.concurrent.LinkedBlockingQueue<>();
}
void scheduleTask(Runnable task) throws InterruptedException {
taskQueue.put(task);
}
boolean tryScheduleTask(Runnable task) {
return taskQueue.add(task);
}
@Override
public void run() {
while (true)
{
try {
Runnable a = taskQueue.take();
if(!(lastTime==-1 || System.currentTimeMillis()-lastTime>timeToWait))
{
//so wait !
synchronized (lastTime)
{
lastTime.wait(timeToWait-(System.currentTimeMillis()-lastTime));
}
}
try{
a.run();
lastTime = System.currentTimeMillis();
}catch (Throwable e)
{
//todo handle e
}
} catch (InterruptedException e) {
break;
}
}
}
}
and also you can use it like this :
TaskTimer t = new TaskTimer(2000);
t.start();
t.scheduleTask(new Runnable() {
@Override
public void run() {
System.out.println("1");
}
});
t.tryScheduleTask(new Runnable() {
@Override
public void run() {
System.out.println("2");
}
});
hope I could help you !
来源:https://stackoverflow.com/questions/53992215/using-a-scheduledexecutorservice-to-run-a-task-on-a-periodic-basis-in-java