В чем разница между этими двумя методами класса Timer
:
schedule(TimerTask task, long delay, long period)
и
scheduleAtFixedRate(TimerTask task, long delay, long period)
Документация не делает различий между ними ясно.
В чем разница между этими двумя методами класса Timer
:
schedule(TimerTask task, long delay, long period)
и
scheduleAtFixedRate(TimerTask task, long delay, long period)
Документация не делает различий между ними ясно.
В документации объясняется разница:
график:
При выполнении с фиксированной задержкой каждое выполнение запланировано относительно фактического времени выполнения предыдущего выполнения. Если исполнение задерживается по какой-либо причине (например, сбор мусора или другая фоновая активность), последующие исполнения также будут отложены.
Итак, предположим, что задержка составляет 5 секунд, и каждая задача занимает 2 секунды, вы получите
TTWWWTTWWWTTWWWTT
где T
означает 1 секунду для выполнения задачи, а W
означает 1 секунду ожидания.
Но теперь предположим, что длинный GC (представленный a G
) происходит и задерживает вторую задачу, третий начинается через 5 секунд после начала второго, как если бы длинный GC не произошел:
TTWWWGGTTWWWTTWWWTT
Третья задача начинается через 5 секунд после второй.
scheduleAtFixedRate:
При выполнении с фиксированной ставкой каждое исполнение запланировано относительно запланированного времени выполнения первоначального выполнения. Если исполнение задерживается по какой-либо причине (например, сбор мусора или другая фоновая активность), два или более исполнения будут выполняться в быстрой последовательности, чтобы "догнать".
Итак, с той же задержкой, что и выше, и тем же GC, вы получите
TTWWWGGTTWTTWWWTT
Третья задача задачи начинается 3 секунды вместо 5 после второго, чтобы догнать.
Спасибо @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
, который вычисляется непосредственно перед запуском этой задачи. Это означает, что время выполнения каждой задачи связано только с предыдущим временем запуска задачи.