Вопрос
Я бы хотел иметь java.utils.Таймер с возможностью сброса времени в Java.Мне нужно установить одноразовое событие, которое будет происходить через X секунд.Если между моментом создания таймера и X секундами ничего не происходит, то событие происходит в обычном режиме.
Однако, если до истечения X секунд я решу, что событие должно произойти через Y секунд, тогда я хочу иметь возможность указать таймеру сбросить свое время, чтобы событие произошло через Y секунд.Например.таймер должен быть способен делать что-то вроде:
Timer timer = new Timer();
timer.schedule(timerTask, 5000); //Timer starts in 5000 ms (X)
//At some point between 0 and 5000 ms...
setNewTime(timer, 8000); //timerTask will fire in 8000ms from NOW (Y).
Я не вижу способа сделать это с помощью utils timer, так как если вы вызовете cancel(), вы не сможете запланировать это снова.
Единственный способ, которым я приблизился к воспроизведению этого поведения, - это использование javax.swing.Timer и включает остановку исходного таймера и создание нового.т. е.:
timer.stop();
timer = new Timer(8000, ActionListener);
timer.start();
Есть ли более простой способ??
Решение
В соответствии с Timer
документация, начиная с Java 1.5, вы должны предпочесть ScheduledThreadPoolExecutor
вместо этого.(Возможно, вы захотите создать этого исполнителя, используя Executors
.newSingleThreadScheduledExecutor()
для удобства использования;это создает нечто очень похожее на Timer
.)
Самое классное, что когда вы планируете выполнение задачи (вызывая schedule()
), он возвращает ScheduledFuture
объект.Вы можете использовать это, чтобы отменить запланированную задачу.Затем вы можете отправить новую задачу с другим временем запуска.
ETA:Тот Самый Timer
документация, связанная с, ничего не говорит о ScheduledThreadPoolExecutor
, однако OpenJDK версия имела это в виду:
Java 5.0 представила
java.util.concurrent
пакетом и одной из содержащихся в нем утилит параллелизма являетсяScheduledThreadPoolExecutor
который является пулом потоков для раз выполнения поставленных задач с заданной скоростью или задержки.Эффективно является более универсальной заменойTimer
/TimerTask
комбинация, поскольку она допускает несколько потоков обслуживания, принимает различные единицы измерения времени и не требует создания подклассовTimerTask
(просто внедритеRunnable
).НастройкаScheduledThreadPoolExecutor
с помощью одного потока это эквивалентноTimer
.
Другие советы
Если ваш Timer
если когда-либо будет выполняться только одна задача, то я бы предложил разделить ее на подклассы:
import java.util.Timer;
import java.util.TimerTask;
public class ReschedulableTimer extends Timer
{
private Runnable task;
private TimerTask timerTask;
public void schedule(Runnable runnable, long delay)
{
task = runnable;
timerTask = new TimerTask()
{
@Override
public void run()
{
task.run();
}
};
this.schedule(timerTask, delay);
}
public void reschedule(long delay)
{
timerTask.cancel();
timerTask = new TimerTask()
{
@Override
public void run()
{
task.run();
}
};
this.schedule(timerTask, delay);
}
}
Вам нужно будет поработать над кодом, чтобы добавить проверки на неправильное использование, но это должно привести к тому, чего вы хотите.Тот Самый ScheduledThreadPoolExecutor
похоже, что в нем также нет встроенной поддержки для перепланирования существующих задач, но аналогичный подход должен работать и там.
Весь фрагмент кода выглядит примерно так ....Я надеюсь, что это будет полноценная помощь
{
Runnable r = new ScheduleTask();
ReschedulableTimer rescheduleTimer = new ReschedulableTimer();
rescheduleTimer.schedule(r, 10*1000);
public class ScheduleTask implements Runnable {
public void run() {
//Do schecule task
}
}
class ReschedulableTimer extends Timer {
private Runnable task;
private TimerTask timerTask;
public void schedule(Runnable runnable, long delay) {
task = runnable;
timerTask = new TimerTask() {
public void run() {
task.run();
}
};
timer.schedule(timerTask, delay);
}
public void reschedule(long delay) {
System.out.println("rescheduling after seconds "+delay);
timerTask.cancel();
timerTask = new TimerTask() {
public void run() {
task.run();
}
};
timer.schedule(timerTask, delay);
}
}
}
Вам нужно запланировать повторяющуюся задачу?В этом случае я рекомендую вам рассмотреть возможность использования Кварц.
Я не думаю, что это возможно сделать с помощью Timer/TimerTask
, но в зависимости от того, чего именно вы хотите достичь, вы можете быть довольны использованием java.util.concurrent.ScheduledThreadPoolExecutor
.
это то, что я опробую.У меня есть класс, который опрашивает базу данных каждые 60 секунд, используя TimerTask.
в моем основном классе я храню экземпляр Timer и экземпляр моего локального подкласса TimerTask.в основном классе есть метод для установки интервала опроса (скажем, от 60 до 30).в нем я отменяю свою TimerTask (которая является моим подклассом, где я перезаписал метод cancel (), чтобы выполнить некоторую очистку, но это не должно иметь значения), а затем делаю его нулевым.я воссоздаю его новый экземпляр и планирую новый экземпляр с новым интервалом в существующем таймере.
поскольку сам Таймер не отменяется, поток, который он использовал, остается активным (как и любые другие временные задачи внутри него), а старая временная задача заменяется новой, которая оказывается такой же, но НЕТРОНУТОЙ (поскольку старая была бы выполнена или запланирована, она больше не является НЕТРОНУТОЙ, как требуется для планирования).
когда я хочу завершить работу всего таймера, я отменяю и обнуляю TimerTask (так же, как я делал при изменении времени, опять же, для очистки ресурсов в моем подклассе TimerTask), а затем я отменяю и обнуляю сам таймер.
Вот пример для сбрасываемого таймера .Попробуйте изменить это для вашего удобства...
package com.tps.ProjectTasks.TimeThread;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
/**
* Simple demo that uses java.util.Timer to schedule a task to execute
* every 5 seconds and have a delay if you give any input in console.
*/
public class DateThreadSheduler extends Thread {
Timer timer;
BufferedReader br ;
String data = null;
Date dNow ;
SimpleDateFormat ft;
public DateThreadSheduler() {
timer = new Timer();
timer.schedule(new RemindTask(), 0, 5*1000);
br = new BufferedReader(new InputStreamReader(System.in));
start();
}
public void run(){
while(true){
try {
data =br.readLine();
if(data != null && !data.trim().equals("") ){
timer.cancel();
timer = new Timer();
dNow = new Date( );
ft = new SimpleDateFormat ("E yyyy.MM.dd 'at' hh:mm:ss a zzz");
System.out.println("Modified Current Date ------> " + ft.format(dNow));
timer.schedule(new RemindTask(), 5*1000 , 5*1000);
}
}catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String args[]) {
System.out.format("Printint the time and date was started...\n");
new DateThreadSheduler();
}
}
class RemindTask extends TimerTask {
Date dNow ;
SimpleDateFormat ft;
public void run() {
dNow = new Date();
ft = new SimpleDateFormat ("E yyyy.MM.dd 'at' hh:mm:ss a zzz");
System.out.println("Current Date: " + ft.format(dNow));
}
}
В этом примере выводятся текущие дата и время каждые 5 секунд...Но если вы введете какие-либо данные в консоли, таймер будет отложен для выполнения заданной задачи ввода...
Я создал собственный класс timer для аналогичной цели;не стесняйтесь использовать его:
public class ReschedulableTimer extends Timer {
private Runnable mTask;
private TimerTask mTimerTask;
public ReschedulableTimer(Runnable runnable) {
this.mTask = runnable;
}
public void schedule(long delay) {
if (mTimerTask != null)
mTimerTask.cancel();
mTimerTask = new TimerTask() {
@Override
public void run() {
mTask.run();
}
};
this.schedule(mTimerTask, delay);
}
}