0

ScheduleExecutorServiceを使用して一定の日数後に深夜にタスクを実行しようとしています。この方法は、最初に実行されるとdelayintervalによってspecifedとして実行されていないように今それはそうScheduledExecutorServiceが予期したとおりに動作しない

public void schedule (int aInterval) 
    { 
     String timezone = TimeZone.getDefault().getID(); 
     ZoneId z = ZoneId.of(timezone); 
     ZonedDateTime now = ZonedDateTime.now(z); 

     LocalDate tomorrow = now.toLocalDate().plusDays(1);  
     ZonedDateTime tomorrowStart = tomorrow.atStartOfDay(z); 
     Duration duration = Duration.between(now , tomorrowStart); 
     long millisecondsUntilTomorrow = duration.toMillis(); 
     long interval; 

     if (aInterval * 24 * 60 * 60 > Long.MAX_VALUE) 
     { 
      interval = Long.MAX_VALUE; 
     } 
     else 
     { 
      interval = aInterval * 24 * 60 * 60; 
     } 

     ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1, new ThreadFactory() { 
      public Thread newThread(Runnable r) { 
       Thread thread = new Thread(r); 
       // allow the JVM to kill the scheduled task 
       thread.setDaemon(true); 
       return thread; 
      });    
     scheduler.scheduleAtFixedRate(new Runnable() 
      { 
       public void run() { 
        System.out.println(String.format("schedule::run() at %1$Td.%1$tm.%1$tY %1$tH:%1$tM:%1$tS \n", System.currentTimeMillis())); 

        doTask(); 
       } 
      }, 
      delay, 
      interval, 
      TimeUnit.SECONDS); 
    } 

:私の方法は、私のTomcat 8の内部で実行され、このようになります。例えば。

... 
schedule::run() at 10.08.2017 17:57:09 
schedule::run() at 10.08.2017 17:57:15 
schedule::run() at 10.08.2017 17:57:21 
schedule::run() at 10.08.2017 17:57:27 
schedule::run() at 10.08.2017 17:57:27 
schedule::run() at 10.08.2017 17:57:33 
schedule::run() at 10.08.2017 17:57:33 
schedule::run() at 10.08.2017 17:57:34 
... 

ので、間隔が何とか時間をかけて短くなってきている:私は私のスタックトレースにdelay=60interval=5を設定すると、それはこのようになります。ここで何が起こっているのですか?私の方法に問題はありますか?

答えて

0

このメソッドを最初に実行すると、delayとintervalで指定されたように実行されないようです。例えば。 stacktraceでdelay = 60とinterval = 5を設定すると、次のようになります。

私は自分の時間変数で非常に明示的になります。この場合、ミリ秒単位で処理する必要がありますので、delayMillis,intervalMillisaIntervalMillisなどをコードに入れてください。数秒の場合はdelaySecsなどを使用しますが、ミリ秒が必要なscheduleAtFixedRate(...) methodに1000を乗算する必要があります。

したがって、間隔は何らかの形で時間とともに短くなります。ここで何が起こっているのですか?私の方法に問題はありますか?

これは、タスクが5ミリ秒ごとにスケジュールを設定しようとしているため、ランダム遅延があなたのdoTask()の実行時間を表示しているということです。それらを60と5 にそれぞれ設定する場合は、代わりに60000と5000を使用する必要があります。私は、私のスケジュールをしようとすると

は()メソッドは、私はTomcatが応答していないし、私のTomcatが正常にシャットダウンされていないと言って私の日食(ネオン3)からメッセージを取得する実行されています。

このわからない

が、私はあなたのTomcatが独自になりますことはありませんどの仕上げるためにあなたのスケジュールされたタスクを待っていると思われます。あなたは、ThreadFactoryを使用し、JVMがシャットダウンするのを待たずにデーモンスレッドを作成することができます。デーモンスレッドの場合は、実行中にすぐに終了する可能性があることに注意してください。あなたが一定のタスクを送信した後

scheduler = Executors.newScheduledThreadPool(1, new ThreadFactory() { 
    public Thread newThread(Runnable r) { 
     Thread thread = new Thread(r); 
     // allow the JVM to kill the scheduled task 
     thread.setDaemon(true); 
     return thread; 
    } 
}); 

また、あなたは、スレッドプールでscheduler.shutdown()を呼び出す必要があります。引き続き実行されますが、他のジョブは提出されません。それは良いパターンです。

実行タスクを適切な方法で停止するにはどうすればよいですか?

あなたのケースでは、デーモンスレッドモードが「適切」かもしれませんが、キャンセルすることもできます。 scheduler.scheduleAtFixedRate(...)メソッドは、を呼び出して停止させるScheduledFutureオブジェクトを返します。 doTask()が終了すると、再度スケジュールされません。cancel(true)を呼び出してスレッドの割り込みフラグを設定することもできますが、あなたのコードはそれを特に処理する必要があります。

もちろん、JVMがシャットダウンしていることを検出して、タスクをキャンセルできるようにする必要があります。あなたは、ハックのビットであるシャットダウンフックを設定することができます。たぶん、それはそれが下っていることを通知するいくつかの方法がありますか?

+0

スレッド工場のアイデアをありがとう、それは正常に動作します。しかし、タイミング機能はまだ機能しません。どのような間隔のtimeunitを使用しても、しばらくしてから関数が狂ってしまい、runnableをより頻繁に実行し続けることになります。 'doTask()'は2〜3秒以上かかることはありませんが、60000ミリ秒の間隔を設定しても、問題は起こり続けます。 – flixe

関連する問題