web-dev-qa-db-ja.com

Javaタイマー

タイマーを使用して、アプリケーションで定期的なイベントをスケジュールしようとしています。ただし、イベントが発生する期間をリアルタイムで調整できるようにしたい(ユーザーの入力に応じて)。

例えば:

public class HelperTimer extends TimerTask
{
    private Timer timer;
    //Default of 15 second between updates
    private int secondsToDelay = 15;

    public void setPeriod(int seconds)
    {
        this.secondsToDelay = seconds;
        long delay = 1000; // 1 second
        long period = 1000*secondsToDelay; // seconds
        if (timer != null) 
        {
            timer.cancel();
        }
        System.out.println(timer);
        timer = new Timer();
        System.out.println(timer);
        timer.schedule(this, delay, period);
    }
    public int getPeriod()
    {
        return this.secondsToDelay;
    }
}

次に、このクラスの新しいインスタンスを開始し、そのsetperiod関数を呼び出します。ただし、これを行うと、Illegalstate例外が発生します。 System.out.println(timer);を見ることができます。確認しているので、確かに2つの異なるタイマーです...新しいTimerインスタンスでスケジュール呼び出しを実行しようとするとIllegalStateExceptionが発生するのはなぜですか!?!?!?!

Java.util.Timer@c55e36
Java.util.Timer@9664a1
Exception in thread "AWT-EventQueue-0" Java.lang.IllegalStateException: Task already scheduled or cancelled
    at Java.util.Timer.sched(Unknown Source)
    at Java.util.Timer.schedule(Unknown Source)
    at HelperTimer.setPeriod(HelperTimer.Java:38)
19
Zak

ここで行っているように、TimerTaskを再利用することはできません。

タイマー の関連部分:

private void sched(TimerTask task, long time, long period) {
    if (time < 0)
        throw new IllegalArgumentException("Illegal execution time.");

    synchronized(queue) {
        if (!thread.newTasksMayBeScheduled)
            throw new IllegalStateException("Timer already cancelled.");

        synchronized(task.lock) {
            //Right here's your problem.
            //  state is package-private, declared in TimerTask
            if (task.state != TimerTask.VIRGIN)
                throw new IllegalStateException(
                    "Task already scheduled or cancelled");
            task.nextExecutionTime = time;
            task.period = period;
            task.state = TimerTask.SCHEDULED;
        }

        queue.add(task);
        if (queue.getMin() == task)
            queue.notify();
    }
}

コードを再利用するのではなく、新しいTimerTaskを作成するように、コードをリファクタリングする必要があります。

21
Kevin Montrose

独自のTimerを内部に持つTimerTaskがあるのは奇妙に思えます。悪いデザイン。 2つを完全に分離し、TimerTask実装をTimerに渡して、ピリオドをいじることに関するすべてのロジックを、そのためのインターフェイスを提供する別のクラス内に配置します。そのクラスにTimerとTimerTaskをインスタンス化し、それらを送信して作業を実行させます。

4
duffymo
    import Java.util.*;
    class TimeSetting 
    {
    public static void main(String[] args)
    {
    Timer t = new Timer();
    TimerTask time = new TimerTask()
    { 
    public void run()
    {
    System.out.println("Executed......");
    }
    };
    t.scheduleAtFixedRate(time, 4000, 3000); 
    // The task will be started after 4 secs and 
    // for every 3 seconds the task will be continuously executed.....
    }
    }
0
deeban