46

私は単に 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;
}

}

最初は、タスクをキャンセルすると実行中のスレッドの実行も停止すると想定していました(「OUCH」部分は含まれていません)。しかし、次のような出力が得られました。

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. 「キャンセル」メソッドは、「開始されていない」ジョブのみを停止できます (メソッドの API 記述と矛盾します)。
  2. cancel メソッドは、run() メソッドから戻らなければならない実行中のスレッドを単純に中断します。

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

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

質問 :

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

4

4 に答える 4

31

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

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

于 2012-03-02T16:16:42.887 に答える
29

あなたが見落としている問題は、協力しているスレッドだけが Java で安全に停止できることです。

実際、Thread API を見ると、Java 1.1 で廃止されたdestroypausestop、 と呼ばれるいくつかのメソッドがあることに気付くでしょう。resumeそれらが非推奨になった理由は、Java 設計者が一般的に安全に使用できないことに気付いたからです。理由については、 「Thread.stop、Thread.suspend、Thread.resume が推奨されないのはなぜですか?」という注で説明されています。.

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


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

于 2012-03-02T16:15:54.337 に答える
14

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

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

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

于 2012-03-02T16:15:07.350 に答える
0

future の一部として実行されるコードが、協調的なキャンセルまたは中断をサポートしていないとします。次に、開始されていないタスクをキャンセルすることが、できる最善の方法です。そのため、このメソッドが存在します。

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

于 2012-03-02T16:15:48.747 に答える