web-dev-qa-db-ja.com

Future.cancel(boolean)メソッドのユーティリティ

私は単にJava.util.concurrentパッケージを探索していました。

クラス 'Future'にはメソッドboolean cancel(boolean mayInterruptIfRunning)があることがわかりました

私が書いたテストコードを添付してください:

package com.Java.util.concurrent;

import Java.util.concurrent.Callable;
import Java.util.concurrent.FutureTask;
import Java.util.concurrent.ScheduledFuture;
import Java.util.concurrent.ScheduledThreadPoolExecutor;

public class FutureTester {

/**
 * @param args
 * @throws InterruptedException
 */
public static void main(String[] args) throws InterruptedException {
    // TODO Auto-generated method stub
    int poolCnt = 1;
    Callable<NumberPrinter> numberPrinter = null;
    ScheduledThreadPoolExecutor schPool = new ScheduledThreadPoolExecutor(
            poolCnt);
    ScheduledFuture<NumberPrinter>[] numPrinterFutures = new ScheduledFuture[poolCnt];
    FutureTask<NumberPrinter>[] futureTask = new FutureTask[poolCnt];

    for (int i = 0; i < poolCnt; i++) {
        numberPrinter = new NumberPrinter();
        futureTask[i] = new FutureTask<NumberPrinter>(numberPrinter);

        /*
         * numPrinterFutures[i] = (ScheduledFuture<NumberPrinter>) schPool
         * .schedule(futureTask[i], 0, TimeUnit.MILLISECONDS);
         */
        numPrinterFutures[i] = (ScheduledFuture<NumberPrinter>) schPool
                .submit(futureTask[i]);
    }

    //Thread.sleep(30);

    if (numPrinterFutures.length > 0) {

        System.out.println("Task completed ? "
                + numPrinterFutures[0].isDone());

        System.out.println("Task cancelled ? "
                + numPrinterFutures[0].cancel(true));

        System.out.println("Is task cancelled ? "
                + numPrinterFutures[0].isCancelled());
    }
}

}

class NumberPrinter implements Callable<NumberPrinter> {

private int counter = 10;

@Override
public NumberPrinter call() throws Exception {
    // TODO Auto-generated method stub

    while (counter > 0) {
        if (Thread.interrupted()) {/*OUCH !!!*/
            return null;
        }
        System.out.println("counter = " + (counter--));
    }

    return this;
}

}

最初に、タスクをキャンセルすると、実行中のスレッドの実行も停止すると想定しました(the 'OUCH' part not included )しかし、私は次のように出力を得ました:

counter = 10
Task completed ? false
counter = 9
Task cancelled ? true
counter = 8
Is task cancelled ? true
counter = 7
counter = 6
counter = 5
counter = 4
counter = 3
counter = 2
counter = 1

Stackoverflow自体の詳細を読むと、

  1. 'cancel'メソッドは、 'unstarted'ジョブのみを停止できます(メソッドのAPI記述と矛盾します)
  2. Cancelメソッドは、実行中のスレッドを中断するだけで、run()メソッドから戻る必要があります。

したがって、「OUCH」部分を含めた-中断のwhileループチェック;出力は次のとおりでした:

Task completed ? false
counter = 10
Task cancelled ? true
Is task cancelled ? true

質問:

実行中のスレッドを停止するために「OUCH」部分に類似した何かを記述することになっている場合、cancelメソッドのユーティリティ/値は何ですか。キャンセルによってスレッドを停止できない場合、FutureTaskでCallableをラップするとどうなりますか?私が見落としている設計/概念/論理部分は何ですか?

37

見落としている問題は、Javaでは協調スレッドのみを安全に停止できることです。

確かに、スレッドAPIを見ると、廃止されたdestroypausestop、およびresumeと呼ばれるメソッドがあることに気付くでしょう。 in Java 1.1。非推奨となった理由は、Javaデザイナーは一般に安全に使用できないことに気付いたからです。理由は注 「Thread.stop、Thread.suspend、およびThread.resumeは非推奨になった理由」

この問題はJavaスレッドモデルに固有のものであり、1つのスレッドが他のスレッドが使用するオブジェクトと対話する能力を抑えることによってのみ回避できます。これを行う...分離する...しかし、主流のJVMは私の知る限りこれらのAPIを実装していません。


これをあなたの質問に戻します。Future.cancelは、canが先物のコンテキストで解決されるという問題のサブセットを解決することです。

26
Stephen C

キャンセルによってスレッドを停止できない場合、FutureTaskでCallableをラップするとどうなりますか?

タスクを実行するスレッドではなく、タスクをキャンセルします。 cancel(true)を使用すると、タスクは開始されません(ただし、キューからは削除されません)。タスクが開始された場合、スレッドが中断されます。タスクは割り込みを無視できますが、プロセス全体を強制終了せずにスレッドを強制終了する方法はありません。

29
Peter Lawrey

cancel(true)を呼び出すと、まだ実行されていない場合はFutureが実行されなくなり、現在実行されている場合はinterruptedになります。この時点で、Futureをキャンセルする負担が開発者にかかります。

スレッドプールであるため、スレッドを停止しても意味がありません(ただし、スレッドを停止する意味がある場合はめったにありません)。キャンセル/割り込みにより、スレッドはrunメソッドを終了しません。 Callableの呼び出しメソッドの実行後、ワークキューから次のアイテムを取り出して処理します。

Cancelメソッドのユーティリティは、スレッドではなく、一部のプロセスがそのCallableの停止を望んでいることを実行中のスレッドに通知することです。そのため、Callableの停止を自分で処理する必要があります。

9
John Vint

将来の一部として実行されるコードが、協調的なキャンセルまたは中断をサポートしていないとします。その後、未開始のタスクをキャンセルするのが最善の方法です。それがこの方法が存在する理由です。

一般的に、キャンセルは厳密に協力的であると考えています。強制的にコードの一部をキャンセルすると、破損した状態になる可能性があります。

0
usr