2

だから私は少し前に質問をしました:ここで「スレッドが長すぎる場合、どうすればスレッドを強制終了させることができますか」という質問がありました

そこに記載されている解決策を実装しましたが、スレッドがタイムアウトするという特定のまれな状況下で、プログラムが失敗したりロックしたりすることがあります (参照: main() メソッドを開いたままにし、プログラムの cron 実行を防止します)。

私が使用しているソースは次のとおりです。

 //Iterate through the array to submit them into individual running threads.
    ExecutorService threadPool = Executors.newFixedThreadPool(12);
    List<Future<?>> taskList = new ArrayList<Future<?>>();
    for (int i = 0; i < objectArray.length; i++) {
        Future<?> task = threadPool.submit(new ThreadHandler(objectArray[i], i));
        taskList.add(task);
        Thread.sleep(500);
    }

    //Event handler to kill any threads that are running for more than 30 seconds (most threads should only need .25 - 1 second to complete.
    for(Future future : taskList){
        try{
            future.get(30, TimeUnit.SECONDS);
        }catch(CancellationException cx){ System.err.println("Cancellation Exception: "); cx.printStackTrace();
        }catch(ExecutionException ex){ System.err.println("Execution Exception: ");ex.printStackTrace();
        }catch(InterruptedException ix){ System.err.println("Interrupted Exception: ");ix.printStackTrace();
        }catch(TimeoutException ex) {future.cancel(true);}
    }
    threadPool.shutdown();
    threadPool.awaitTermination(60, TimeUnit.SECONDS);

私の質問は次のとおりです。このコードが実装されているのに、エグゼキュータ サービスが 30 秒で処理を中断しないのはなぜですか。

4

3 に答える 3

4

ワーカー スレッドがまだ実行されていると思われるためです。呼び出しfuture.cancel(true);ていますが、スレッドに割り込みフラグを設定するだけです。実行中のコードを積極的に中断することはありません。コードを「中断」するもう 1 つの方法は、いくつかのvolatile boolean shutdownフラグを true に設定し、コードでそれをテストすることです。スレッドの中断の詳細については、こちらを参照してください。

ThreadHandlerコードが割り込みを正しく処理することを確認する必要があります。たとえば、Thread.currentThread().isInterrupted()ループや他のコード ブロックをチェックする必要があります。InterruptedExceptionまた、割り込みを飲み込むだけでなく、正しく処理していることも確認する必要があります。

スレッド割り込みの詳細については、こちらの回答を参照してください。

于 2012-10-16T14:12:36.253 に答える
1

意図しない可能性がある各タスクのタイムアウトの量が増えています。代わりに、タイムアウト後にスレッド プールをシャットダウンし、残りをキャンセルできます。

threadPool.shutdown();
threadPool.awaitTermination(30, TimeUnit.SECONDS);
threadPool.shutdownNow(); // interrupt any running tasks.
于 2012-10-16T14:24:42.197 に答える
0

『Java Concurrency in Practice』という本には、タスクのキャンセルに関する章全体があります。私が読んだことから、タスクのキャンセルは、タスクが常に終了していることを確認するために、finally ブロックにある必要があります。

    try{
            future.get(30, TimeUnit.SECONDS);

        } catch (TimeoutException e) {
           // log error message and falls through to finally block
        } catch (ExecutionException e) {
            throw e;
        } finally {
            future.cancel(true); // interrupt task
        }

InterruptedException の処理中に中断ステータスを復元する必要があります。

           catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }

ThreadHandler タスクで Thread.currentThread().isInterrupted() フラグをチェックし、true の場合は InterruptedException をスローして、割り込みステータスを伝達します。

于 2012-10-16T18:32:14.633 に答える