我需要创建多个任务,每个任务每n
秒执行一次。我决定使用ScheduledExecutorService
来安排任务执行。问题是任务不及时执行。我认为原因是处理器时间不够,但实际 CPU使用率约为 4-5%。
我的调度程序创建者:
class SchedulersCreator {
private final ScheduledExecutorService scheduler
= Executors.newScheduledThreadPool(1);
public SchedulersCreator(int tasksAmount, int repeatCount) {
for (int taskId = 0; taskId <= tasksAmount; taskId++) {
// create new task, that executes every 2 seconds
MyTask task = new MyTask(scheduler, repeatCount, 2, taskId);
// execute new task
task.run();
}
}
public static void main(String[] args) {
System.out.println("Program started");
// create & start 10 tasks, each of the executes 10 times with period 2 seconds
SchedulersCreator scheduler = new SchedulersCreator(10, 10);
System.out.println("All tasks created & started");
}
}
我的任务:
class MyTask implements Runnable {
// number of executions
private int executesTimesLeft;
// execution period
private final int periodSeconds;
// task id
private final int id;
// scheduler
private ScheduledExecutorService scheduler;
// field to measure time between executions
private long lastExecution = 0;
public MyTask(ScheduledExecutorService scheduler, int executes, int periodSeconds, int id) {
this.executesTimesLeft = executes;
this.id = id;
this.periodSeconds = periodSeconds;
this.scheduler = scheduler;
}
private void performAction() {
long before = System.currentTimeMillis();
long time = (before - lastExecution) % 1_000_000;
lastExecution = before;
// Simulates useful calculations
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
}
long after = System.currentTimeMillis();
if (id % 100_000 == 0) {
long duration = after - before;
System.out.println("Time since prev execution:\t" + time + "\t"
+ "Task " + id + ": "
+ executesTimesLeft + " executions lefts; "
+ "current duration\t" + duration);
}
}
@Override
public void run() {
// perform useful calculation in another thread
new Thread(() -> performAction()).run();
executesTimesLeft--;
if (executesTimesLeft > 0) { // schedule next task execution
scheduler.schedule(this, periodSeconds, SECONDS);
}
}
}
ideone上的代码:https://ideone.com/s3iDif。 我预计执行时间约为2秒,但实际结果为3-4秒。
节目输出:
...
Time since prev execution: 3028 Task 0: 2 executions lefts; current duration 1000
Time since prev execution: 4001 Task 0: 1 executions lefts; current duration 1001
答案 0 :(得分:2)
您的代码没有正确使用调度程序。
// perform useful calculation in another thread
new Thread(() -> performAction()).run();
这实际上并没有在新线程中运行代码。为此,您需要致电start()
,而不是run()
。调用run()
会使代码在当前线程中执行,与您刚刚编写performAction();
时没有区别。
但是,您根本不应该明确创建新线程。您可以而且应该在MyTask.run()
中完成工作。
任务不需要了解调度程序或其频率。更改此代码:
MyTask task = new MyTask(scheduler, repeatCount, 2, taskId);
// execute new task
task.run();
为:
MyTask task = new MyTask(repeatCount, taskId);
Future<?> future = scheduler.scheduleAtFixedRate(task, 0, 2, SECONDS);
您希望重复任务,因此请使用执行此操作的调度程序方法。这将允许调度程序根据任务运行的时间来调整任务之间的时间。
将performAction()
全部移至MyTask.run()
。如果您希望任务停止重复,请使用future
取消它。