使用 ScheduledExecutorService 在 Java 中定期 运行 执行任务
Using a ScheduledExecutorService to run a task on a periodic basis in Java
我正在开发一个程序,该程序将从数据源读取数据,并在读取数据时发布该数据。我有一个 reader 和一个 writer,reader 产生几个线程来读取它需要读取的所有数据,将数据放入队列中,writer 从队列中读取数据并发布它.
我有一个控制器用于我的 readers 和一个控制器用于我的作家。控制器实现了 Callable
接口,但可以实现 Runnable
接口,因为我的调用 return 是 Void
.
我想用一个执行器来运行两个控制器。 reader 控制器将需要每 X 分钟调用一次(并且 X 大于控制器到达 运行 所花费的时间)。
现在,我正在创建 Callables
的列表,将它们发送到一个 ExecutorService,即:
List<Future<Void>> futures = ExecutorService es = new Executors.newFixedThreadPoll(2);
for(Future<Void> future: futures) {
try {
future.get();
} catch (Exception e) {
// log the error
}
}
我如何将它变成一个调度执行器,运行每 30 分钟(或更准确地说,在最后一个作业 运行 后 30 分钟)调用一次?
好的,您可以通过多种方式完成。但是如果性能 很重要 你可以在你自己的线程中处理这些事情,如下所示:
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;
}
}
}
}
你也可以这样使用它:
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");
}
});
希望能帮到你!
我正在开发一个程序,该程序将从数据源读取数据,并在读取数据时发布该数据。我有一个 reader 和一个 writer,reader 产生几个线程来读取它需要读取的所有数据,将数据放入队列中,writer 从队列中读取数据并发布它.
我有一个控制器用于我的 readers 和一个控制器用于我的作家。控制器实现了 Callable
接口,但可以实现 Runnable
接口,因为我的调用 return 是 Void
.
我想用一个执行器来运行两个控制器。 reader 控制器将需要每 X 分钟调用一次(并且 X 大于控制器到达 运行 所花费的时间)。
现在,我正在创建 Callables
的列表,将它们发送到一个 ExecutorService,即:
List<Future<Void>> futures = ExecutorService es = new Executors.newFixedThreadPoll(2);
for(Future<Void> future: futures) {
try {
future.get();
} catch (Exception e) {
// log the error
}
}
我如何将它变成一个调度执行器,运行每 30 分钟(或更准确地说,在最后一个作业 运行 后 30 分钟)调用一次?
好的,您可以通过多种方式完成。但是如果性能 很重要 你可以在你自己的线程中处理这些事情,如下所示:
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;
}
}
}
}
你也可以这样使用它:
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");
}
});
希望能帮到你!