ScheduledExecutorService执行任务较晚,CPU和CPU较低。 RAM使用情况

时间:2018-01-14 13:30:13

标签: java concurrency scheduledexecutorservice

我需要创建多个任务,每个任务每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

1 个答案:

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