Таймер Java
1. Таймер - основы
2. Запланируйте задачу один раз
Начнем сrunning a single task с помощьюTimer:
@Test
public void givenUsingTimer_whenSchedulingTaskOnce_thenCorrect() {
TimerTask task = new TimerTask() {
public void run() {
System.out.println("Task performed on: " + new Date() + "n" +
"Thread's name: " + Thread.currentThread().getName());
}
};
Timer timer = new Timer("Timer");
long delay = 1000L;
timer.schedule(task, delay);
}
Обратите внимание, что если мы запускаем это тест JUnit, мы должны добавить вызовThread.sleep(delay * 2), чтобы разрешить потоку Timer выполнить задачу до того, как тест Junit перестанет выполняться.
3. Запланируйте повторяющееся задание через определенный промежуток времени
Далее - давайтеschedule a task to run at a pre-defined interval.
Мы будем использовать APIscheduleAtFixedRate(repeatedTask, delay, period), который планирует повторное выполнение задачи с фиксированной скоростью, начиная с указанной задержки. Последующие казни происходят через равные промежутки времени, разделенные указанным периодом:
@Test
public void givenUsingTimer_whenSchedulingRepeatedTask_thenCorrect(){
TimerTask repeatedTask = new TimerTask() {
public void run() {
System.out.println("Task performed on " + new Date());
}
};
Timer timer = new Timer("Timer");
long delay = 1000L;
long period = 1000L;
timer.scheduleAtFixedRate(repeatedTask, delay, period);
}
Обратите внимание, что - если выполнение по какой-либо причине задерживается (например, сборка мусора или другая фоновая активность), два или более выполнения будут выполняться в быстрой последовательности, чтобы «догнать».
3.1. Запланировать ежедневное задание
Далее - давайтеrun a task once a day:
@Test
public void givenUsingTimer_whenSchedulingDailyTask_thenCorrect() {
TimerTask repeatedTask = new TimerTask() {
public void run() {
System.out.println("Task performed on " + new Date());
}
};
Timer timer = new Timer("Timer");
long delay = 1000L;
long period = 1000L * 60L * 60L * 24L;
timer.scheduleAtFixedRate(repeatedTask, delay, period);
}
4. ОтменитеTimer иTimerTask
Выполнение задачи может быть отменено несколькими способами:
4.1. ОтменитьTimerTask внутриRun
Вызывая методTimerTask.cancel() внутри реализации методаrun() самогоTimerTask:
@Test
public void givenUsingTimer_whenCancelingTimerTask_thenCorrect()
throws InterruptedException {
TimerTask task = new TimerTask() {
public void run() {
System.out.println("Task performed on " + new Date());
cancel();
}
};
Timer timer = new Timer("Timer");
timer.scheduleAtFixedRate(task, 1000L, 1000L);
Thread.sleep(1000L * 2);
}
4.2. ОтменитьTimer
Вызывая методTimer.cancel() для объектаTimer:
@Test
public void givenUsingTimer_whenCancelingTimer_thenCorrect()
throws InterruptedException {
TimerTask task = new TimerTask() {
public void run() {
System.out.println("Task performed on " + new Date());
}
};
Timer timer = new Timer("Timer");
timer.scheduleAtFixedRate(task, 1000L, 1000L);
Thread.sleep(1000L * 2);
timer.cancel();
}
4.3. Остановить потокTimerTask внутриRun
Вы также можете остановить поток внутри метода задачиrun, тем самым отменив всю задачу:
@Test
public void givenUsingTimer_whenStoppingThread_thenTimerTaskIsCancelled()
throws InterruptedException {
TimerTask task = new TimerTask() {
public void run() {
System.out.println("Task performed on " + new Date());
// TODO: stop the thread here
}
};
Timer timer = new Timer("Timer");
timer.scheduleAtFixedRate(task, 1000L, 1000L);
Thread.sleep(1000L * 2);
}
Обратите внимание на инструкцию TODO в реализацииrun - чтобы запустить этот простой пример, нам нужно будет фактически остановить поток.
В реальной реализации настраиваемого потока должна поддерживаться остановка потока, но в этом случае мы можем игнорировать устаревание и использовать простой APIstop в самом классе Thread.
5. Timer VSExecutorService
Вы также можете использовать ExecutorService для планирования задач таймера вместо использования таймера.
Вот краткий пример того, как выполнять повторяющуюся задачу с заданным интервалом:
@Test
public void givenUsingExecutorService_whenSchedulingRepeatedTask_thenCorrect()
throws InterruptedException {
TimerTask repeatedTask = new TimerTask() {
public void run() {
System.out.println("Task performed on " + new Date());
}
};
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
long delay = 1000L;
long period = 1000L;
executor.scheduleAtFixedRate(repeatedTask, delay, period, TimeUnit.MILLISECONDS);
Thread.sleep(delay + period * 3);
executor.shutdown();
}
Итак, каковы основные различия междуTimer иExecutorService решением:
-
Timer может быть чувствительным к изменениям системных часов; ScheduledThreadPoolExecutor не
-
Timer имеет только один поток выполнения; ScheduledThreadPoolExecutor можно настроить с любым количеством потоков
-
Исключения времени выполнения, возникающие внутриTimerTask, убивают поток, поэтому следующие запланированные задачи не будут выполняться дальше; сScheduledThreadExecutor - текущая задача будет отменена, но остальные продолжат выполнение
6. Заключение
В этом руководстве проиллюстрированы многочисленные способы использования простой, но гибкой инфраструктурыTimer иTimerTask, встроенной в Java, для быстрого планирования задач. Конечно, в мире Java есть гораздо более сложные и полные решения, если они вам нужны - такие какthe Quartz library - но это очень хорошее место для начала.
Реализацию этих примеров можно найти вthe github project - это проект на основе Eclipse, поэтому его должно быть легко импортировать и запускать как есть.