0

ExecutorService を使用して TimeoutTask を実装しました。以下のメソッドでは、TimeoutTask を送信しています。指定された時間内にタイムアウトになった場合は、タスクをキャンセルしてエグゼキュータをシャットダウンします。

private boolean waitForProcessToBeCompleted(long timeOut) {
            boolean result = false;
            ExecutorService executor = Executors.newSingleThreadExecutor();
            // Create a FutureTask which will be run
            FutureTask<Boolean> futureTask = new FutureTask<Boolean>(new TimeoutTask());
            executor.submit(futureTask); // Run the FutureTask
            try {
                result = futureTask.get(timeOut, TimeUnit.MILLISECONDS); // Check if FutureTask completed in the given time
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            } catch (TimeoutException e) {
                futureTask.cancel(true);
                result = true;  // Return True only when timed out
            } finally {
                executor.shutdownNow(); // Stop the executor
            }
            return result;
        }

とても調子が良く、特に問題はありません。

ただし、これが最適なコード設計であるかどうかを知りたいです。ExecutorService.submit() によって返される Future を使用して、Callable の戻り値を取得するか、TimeoutTask をタイムアウトにする方がよいのではないかと思っていました。例えば

            Future<?> futureTask = executor.submit(new TimeoutTask()); // Run the FutureTask
            try {
                result = futureTask.get(timeOut, TimeUnit.MILLISECONDS); // Check if FutureTask completed in the given time
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            } catch (TimeoutException e) {
                futureTask.cancel(true);
                result = true;  // Return True only when timed out
            } finally {
                executor.shutdownNow(); // Stop the executor
            }
            return result;

私はJDK7を使用しています。

4

3 に答える 3

0

ExecutorServiceのinvokeAllメソッドを使用して、タイムアウトを超えたタスクを自動的にキャンセルできます。これにより、スレッドプールをシャットダウンせずにタスクをキャンセルできます (選択した場合は、同じスレッドプールを他のものに再利用できます)。

private boolean waitForProcessToBeCompleted(long timeOut) {
  ExecutorService executor = Executors.newSingleThreadExecutor();
  List<FutureTask> tasks = new ArrayList<>();
  tasks.add(new SomeFutureTaskThing()));
  List<Future<Boolean>> results;
  try {
    results = executor.invokeAll(tasks, timeOut, TimeUnit.SECONDS);
  } catch (InterruptedException e) {
    Thread.currentThread().interrupt(); // Restore interrupt status.
    return null;
  } catch (ExecutionException e) {
    throw new RuntimeException(e.getCause());
  }
  Future<Boolean> result = results.get(0);
  try {
    return result.get();
  } catch (CancellationException e) {
    System.err.println("Timed out");
    return null;
  }
}
于 2015-06-05T16:10:36.313 に答える
0

私は使用したいと思いCountDownLatchます:

List<List<String>> elements = MyPartition.partition(bigObjectList, size); 
List<Future<?>> tasks = new ArrayList<Future<?>>();
ExecutorService executor = Executors.newSingleThreadExecutor();
CountDownLatch doneSignal =  new CountDownLatch(10);
for(List<String> l: elements) {         
   ReadTask worker = new ReadTask(doneSignal, l);
   tasks.add(executor.submit(worker));
}   

long timeout = 10000;
doneSignal.await(timeout, TimeUnit.SECONDS);
boolean notFinished = false;
if(doneSignal.getCount() > 0) {
  for(Future<?> fut : tasks) {
    if(!fut.isDone()) {
      System.out.println("Sub Thread " + fut + " has not finshed!");
      fut.cancel(true);             
      notFinished = true;
    }
  }
}
于 2013-04-16T10:43:12.760 に答える
0

のコードをfutureTask.cancel見ると、タスクを実行しているスレッドを中断しようとしていることがわかります。この割り込みは、タスク規則が明示的または暗黙的に (sleep() または wait() の呼び出しを介して) 割り込みフラグをチェックする場合に機能する可能性があります。Java では、メソッドの実行を安全に停止する方法は他にありません。

そのため、個別のシングルスレッド エグゼキュータを毎回作成することなく、同じ機能を実装できます。代わりに、メソッド内から TimerTask を実行しますwaitForProcessToBeCompleted。タイムアウトの通知を受けるには、監視タスクを SheduledExecutorService に送信します。監視タスクは、TimerTask を実行するスレッドに割り込む必要があります。タイムアウト前にタスクが完了した場合は、監視タスクをキャンセルします。

この方法では、SheduledExecutorService が必要になりますが、プロセッサ サイクルをほとんど消費せず、アプリケーション全体で再利用できます。

于 2013-04-16T10:55:05.770 に答える