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 取消它。