Подтвердить что ты не робот

В чем разница между расписанием и расписаниемAtFixedRate?

В чем разница между этими двумя методами класса Timer:

schedule(TimerTask task, long delay, long period)

и

scheduleAtFixedRate(TimerTask task, long delay, long period)

Документация не делает различий между ними ясно.

4b9b3361

Ответ 1

В документации объясняется разница:

график:

При выполнении с фиксированной задержкой каждое выполнение запланировано относительно фактического времени выполнения предыдущего выполнения. Если исполнение задерживается по какой-либо причине (например, сбор мусора или другая фоновая активность), последующие исполнения также будут отложены.

Итак, предположим, что задержка составляет 5 секунд, и каждая задача занимает 2 секунды, вы получите

TTWWWTTWWWTTWWWTT

где T означает 1 секунду для выполнения задачи, а W означает 1 секунду ожидания.

Но теперь предположим, что длинный GC (представленный a G) происходит и задерживает вторую задачу, третий начинается через 5 секунд после начала второго, как если бы длинный GC не произошел:

TTWWWGGTTWWWTTWWWTT

Третья задача начинается через 5 секунд после второй.

scheduleAtFixedRate:

При выполнении с фиксированной ставкой каждое исполнение запланировано относительно запланированного времени выполнения первоначального выполнения. Если исполнение задерживается по какой-либо причине (например, сбор мусора или другая фоновая активность), два или более исполнения будут выполняться в быстрой последовательности, чтобы "догнать".

Итак, с той же задержкой, что и выше, и тем же GC, вы получите

TTWWWGGTTWTTWWWTT

Третья задача задачи начинается 3 секунды вместо 5 после второго, чтобы догнать.

Ответ 2

Спасибо @Nizet ответ, я написал пример кода для некоторых людей, которые хотят практиковать и учиться.

import java.util.Timer;
import java.util.TimerTask;

public class TimerTest {

    public static void main(String args[]){
        TimerTest.DelayTask task = new DelayTask();
        Timer timer = new Timer();
        /**
         * Use schedule or scheduletAtFixedrate and check the printed result
         */
        timer.schedule(task, 0, 5000);
        //timer.scheduleAtFixedRate(task, 0, 5000);
    }

    public static boolean stop = false;

    public static void delayOneSec(String status){
        try{
            System.out.print(status);
            Thread.sleep(1000);
        }catch(Exception e){
            e.printStackTrace();
        }
    }

    static class DelayTask extends TimerTask{
        int count = 2;

        @Override
        public void run() {
            // TODO Auto-generated method stub
            stop = true;
            for(int i = 0; i < count; i++){
                TimerTest.delayOneSec("T");
            }
            if(count == 2){
                count = 6;
            }else{
                count = 2;
            }
            stop = false;
            new PrintW().start();
        }
    }

    static class PrintW extends Thread{
        @Override
        public void run(){
            while(!stop){
                TimerTest.delayOneSec("W");
            }
        }

    }
}

Сама задача повторится и займет 2 секунды или 6 секунд. Посмотрим результат каждого сценария.

При использовании timer.schedule(task, 0, 5000); вывод TTWWWTTTTTTTTWWWTTTTTTTTWWWTTTTTTTT. Как вы можете видеть, таймер соблюдает правила, как показано ниже, до тех пор, пока задача не завершится вовремя, подождите до period, немедленно запустите следующую задачу, если текущая задача длится больше, чем period.

При использовании timer.scheduleAtFixedRate(task, 0, 5000); вывод TTWWWTTTTTTTTWWTTTTTTTTWWTTTTTTTTWWTTTTTTTTWWTTTTTTTTWWTTTTTTTT. Сейчас все немного по-другому. Javadoc

два или более исполнения будут выполняться в быстрой последовательности, чтобы "догнать".

вступает в силу здесь. Как вы можете видеть, игнорируя первый TTWWW, каждая из двух задач будет печатать TTTTTTTTWW и длится 10 секунд (два периода).

Позвольте вставить исходный код Timer.

public void schedule(TimerTask task, Date firstTime, long period) {
    if (period <= 0)
        throw new IllegalArgumentException("Non-positive period.");
    sched(task, firstTime.getTime(), -period);
}


public void scheduleAtFixedRate(TimerTask task, long delay, long period) {
    if (delay < 0)
        throw new IllegalArgumentException("Negative delay.");
    if (period <= 0)
        throw new IllegalArgumentException("Non-positive period.");
    sched(task, System.currentTimeMillis()+delay, period);
}

Как вы можете видеть, period переносится на отрицательное значение в методе schedule. Посмотрим, какая разница при планировании.

Ниже код находится в mainloop TimerThread,

currentTime = System.currentTimeMillis();
executionTime = task.nextExecutionTime;
if (taskFired = (executionTime<=currentTime)) {
    if (task.period == 0) { // Non-repeating, remove
        queue.removeMin();
        task.state = TimerTask.EXECUTED;
    } else { // Repeating task, reschedule
        queue.rescheduleMin(
        task.period<0 ? currentTime   - task.period
                      : executionTime + task.period);
           }
    }
}

Здесь, где происходит магия, для метода schedule следующее время выполнения задачи основано на currentTime, который вычисляется непосредственно перед запуском этой задачи. Это означает, что время выполнения каждой задачи связано только с предыдущим временем запуска задачи.