1

さて、私は時間をかけて周りを見回しましたが、明確な解決策を見つけることができませんでした. 以前に別の質問を投稿しましたが、それは少し異なる問題です。

問題: 定期的に発生する条件をポーリングしたい。その条件がまだ false の場合は、再度スケジュールを変更します。true の場合、スケジューリングを停止します。しかし、私はまた、決定的な時間だけ待ちたいと思っています。これが私が書いたものです

 final ScheduledExecutorService service = Executors.newScheduledThreadPool(1);

  final Future<?> future = service.schedule(new Runnable() {
        @Override
        public void run() {
            if (conditionFalse()) {
                System.out.println("its false. Rescheduling");
                service.schedule(this, 2, TimeUnit.SECONDS);
            } else {
                System.out.println("true. Exiting");
            }
        }
    }, 2, TimeUnit.SECONDS);

   //Wait only for 5 seconds 
   future.get(5, TimeUnit.SECONDS); // does not work
   //does not work either
     service.schedule(new Runnable() {
        @Override
        public void run() {
            future.cancel(true);
        }
    }, 5, TimeUnit.SECONDS);

これは、条件が満たされるまで自分自身を再スケジュールし続けます。なぜ機能しないのかについての提案はありますか? 5 秒だけ待ってからタスクの実行を停止するにはどうすればよいですか?

4

1 に答える 1

1

Future.get戻ると、最初のタスクは終了していますが、同じ を使用して別のタスクをスケジュールしている可能性がありますRunnable。最初の (終了した) タスクを表すが、新しくスケジュールされたタスクではないためcancel、最初に呼び出しても効果はありません。Futureを呼び出すたびにschedule、新しい が返されることに注意してくださいFuture

最後に、なぜタスクをそれほど複雑にするのかは明らかではありません。バックグラウンド スレッドの大きな利点は、プログラムの実行全体に影響を与えずにブロック操作を実行できることです。したがって、条件を 2 秒ごとに再チェックする場合は、2 秒ごとのチェック ロジックを実装する1 つのバックグラウンド タスクを作成するだけです。2 秒待つとそのスレッドがブロックされますが、問題ありません。これはバックグラウンド スレッドです。

ExecutorService service=Executors.newFixedThreadPool(1);
Future<?> f=service.submit(new Runnable() {
  public void run() {
    try {
      while(conditionFalse()) {
        System.out.println("it’s false, will wait");
        Thread.sleep(TimeUnit.SECONDS.toMillis(2));
      }
      System.out.println("true. exiting.");
    } catch(InterruptedException ex) {
      System.out.println("interrupted. exiting.");
    }
  }
});
try {
  try {
    f.get(5, TimeUnit.SECONDS);
    System.out.println("conditions met even before trying to cancel");
  } catch(TimeoutException ex) {
    System.out.println("canceling");
    System.out.println(f.cancel(true)?
      "canceled before conditions met": "conditions met before canceled");
  }
} catch(InterruptedException | ExecutionException ex) {
  throw new AssertionError(ex);
}

タスクをキャンセルするとsleep、質問の内容である がすぐに終了します。条件が満たされておらず、タスクがキャンセルされていない限り、何かを再スケジュールする必要はありません。ループはそのまま実行され続けます。

より多くのタスクがある場合は、executor のスレッド数を増やしてください。リソース消費のように感じるかもしれませんが、スリープ状態のスレッドは多くのリソースを消費せず、タスクの実行間でもスリープScheduledExecutor状態を維持しThreadます。タスクを再スケジュールしない場合でも、いくつかの操作を節約できます。

重要なのは、コードが明確で理解しやすいかどうかであり、単純なループが (機能していない) 再スケジュール コードよりも優先されると思います。

于 2014-06-03T17:55:35.027 に答える