ScheduledExecutorService 执行任务较晚,CPU 和 RAM 使用率低
ScheduledExecutorService execute tasks late, with low CPU & RAM usage
我需要创建 多个 任务,其中 每个 每 n
秒执行一次。我决定使用 ScheduledExecutorService
来安排任务执行。问题是任务 没有 及时执行。我认为原因是处理器时间不够,但 actual 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
您的代码没有正确使用调度程序。
// 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
取消它。
我需要创建 多个 任务,其中 每个 每 n
秒执行一次。我决定使用 ScheduledExecutorService
来安排任务执行。问题是任务 没有 及时执行。我认为原因是处理器时间不够,但 actual 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
您的代码没有正确使用调度程序。
// 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
取消它。