40

java.utils.Timer で時間をリセットできるようにしたいのですが、X 秒後に 1 回限りのイベントが発生するように設定する必要があります。タイマーが作成されてから 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 タイマーを使用してこれを行う方法がわかりません。cancel() を呼び出した場合、再度スケジュールすることはできません。

この動作を再現する唯一の方法は、javax.swing.Timer を使用することであり、元のタイマーを停止して新しいタイマーを作成する必要があります。すなわち:

timer.stop();
timer = new Timer(8000, ActionListener);
timer.start();

もっと簡単な方法はありますか??

4

8 に答える 8

50

ドキュメントによると、TimerJava 1.5 以降では、ScheduledThreadPoolExecutor代わりに を使用する必要があります。(このエグゼキュータを使いやすくするために を使用して作成することをお勧めします。これは によく似たものを作成します。)Executors.newSingleThreadScheduledExecutor()Timer

すばらしいことに、( を呼び出してschedule()) タスクをスケジュールすると、オブジェクトが返されScheduledFutureます。これを使用して、スケジュールされたタスクをキャンセルできます。その後、別のトリガー時間で新しいタスクを自由に送信できます。

ETA:Timerリンク先のドキュメントには について何も書かれていませんScheduledThreadPoolExecutorが、OpenJDKバージョンには次のように書かれていました。

Java 5.0 でこのjava.util.concurrentパッケージが導入されました。その中の同時実行ユーティリティの 1 つは ScheduledThreadPoolExecutor、特定の速度または遅延でタスクを繰り返し実行するためのスレッド プールです。 これは、複数のサービス スレッドを許可し、さまざまな時間単位を受け入れ、サブクラス化を必要としない(単に を実装する) ため、実質的にはTimer/の組み合わせのより用途の広い代替手段となります。1 つのスレッドで構成 すると、 と同等になり ます。TimerTaskTimerTaskRunnableScheduledThreadPoolExecutorTimer

于 2008-08-28T11:52:00.717 に答える
17

Timer実行するタスクが 1 つしかない場合は、サブクラス化することをお勧めします。

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タスクを再スケジュールするためのサポートも組み込まれていないようですが、同様のアプローチがそこでも機能するはずです。

于 2008-08-28T12:25:23.693 に答える
3

コードスニペット全体は次のようになります....完全に役立つことを願っています

{

        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);        
        }
      }


}
于 2012-11-27T11:40:20.403 に答える
1

定期的なタスクをスケジュールする必要がありますか? その場合は、Quartzの使用を検討することをお勧めします。

于 2008-08-28T10:54:30.247 に答える
1

これは私が試しているものです。TimerTask を使用して 60 秒ごとにデータベースをポーリングするクラスがあります。

私のメイン クラスでは、Timer のインスタンスと、TimerTask のローカル サブクラスのインスタンスを保持しています。メインクラスには、ポーリング間隔を設定するメソッドがあります (たとえば、60 から 30 に変更します)。その中で、TimerTask (これは私のサブクラスであり、cancel() メソッドを上書きしてクリーンアップを行いましたが、それは問題ではありません) をキャンセルしてから、null にします。その新しいインスタンスを再作成し、既存のタイマーの新しい間隔で新しいインスタンスをスケジュールします。

Timer 自体は取り消されないため、使用していたスレッドはアクティブなままであり (その中の他の TimerTasks も同様です)、古い TimerTask は新しいものに置き換えられますが、たまたま同じものですが、VIRGIN (古いものは実行またはスケジュールされており、スケジューリングに必要な VIRGIN ではありません)。

タイマー全体をシャットダウンする場合は、TimerTask をキャンセルして null にし (TimerTask のサブクラスのリソースをクリーンアップするためにタイミングを変更したときと同じです)、Timer 自体をキャンセルして null にします。

于 2009-04-16T14:09:11.343 に答える
1

でそれを行うことは不可能だと思いますがTimer/TimerTask、正確に何を達成したいかによっては、 を使用して満足するかもしれませんjava.util.concurrent.ScheduledThreadPoolExecutor

于 2008-08-28T11:47:18.623 に答える
0

これは Resetable Timer の例です。あなたの納得のためにそれを変更してみてください...

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 秒ごとに出力します...しかし、コンソールに入力を与えると、指定された入力タスクを実行するためにタイマーが遅れます...

于 2012-12-05T09:53:52.823 に答える