14

Futures を ExecutorService からハッシュ マップにプッシュします。後で、ハッシュ マップ内から Future の cancel を呼び出すことができます。結果は true ですが、Future cancel() が何の効果もなかったかのように、後で Callable プロシージャ内のブレークポイントにヒットしました。ここでは 2 つの異なる参照の場合であると思います (参照 ID はブレークポイント時に同じとしてリストされますが)、一部の専門家が参加できるかどうか疑問に思っていました。コードは次のようになります。

ExecutorService taskExecutor = Executors.newCachedThreadPool();
Map <String, Future<Object>> results = new HashMap <String, Future<Object>>();      

Future<Object> future = taskExecutor.submit(new MyProcessor(uid));
results.put(uid, future);

処理を続行できるようにし (タスクが渡されたときにタスクをサブミットするループです)、後で次のメソッドを呼び出して外部ソースからキャンセルを試みる場合があります。

public static synchronized boolean cancelThread(String uid) {
    Future<Object> future = results.get(uid);
    boolean success = false;
    if (future != null) {
        success = (future.isDone() ? true : future.cancel(true));
        if (success)
            results.remove(uid);
    }
    return success;     
}

しかし、future.cancel() が呼び出された後でも、MyProcessor.call() 内で「キャンセルされていない」パスに遭遇します。つまり、実際にはキャンセルされていません。

これのどこが間違っているのですか?これを行うより良い方法はありますか?

4

2 に答える 2

23

Future cancel() が何の効果もなかったかのように、後で Callable プロシージャ内でブレークポイントにヒットしました。

Future.cancel(true)キューにあり、まだ実行されていないジョブを削除しますが、ジョブが既に実行されている場合は、ジョブを実行してThread.interrupt()いるスレッドで同等の処理を行います。これにより、スレッドに割り込みビットが設定され、、、およびsleep()その他wait()のメソッドがスローされInterruptedExceptionます。

スレッドを停止しないことを理解することが重要です。スレッドループで割り込みフラグを積極的にチェックするか、適切に処理する必要がありますInterruptedException

詳細については、SO の回答を参照してください: How to suspend thread using thread's id?

于 2012-06-22T14:45:31.823 に答える
1

FutureTask :: boolean cancel(boolean mayInterruptIfRunning)interrupt現在実行中のスレッドで実行されます。

FutureTask.java
public boolean cancel(boolean mayInterruptIfRunning) {
    if (!(state == NEW &&
          UNSAFE.compareAndSwapInt(this, stateOffset, NEW,
              mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
        return false;
    try {    // in case call to interrupt throws exception
        if (mayInterruptIfRunning) {
            try {
                Thread t = runner;
                if (t != null)
                    t.interrupt();     ////////////HERE/////////////
            } finally { // final state
                UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
            }
        }
    } finally {
        finishCompletion();
    }
    return true;
}

JavaDocは次のように述べていますinterrupt

public void interrupt()

このスレッドに割り込みます。現在のスレッドがそれ自体を中断していない限り (これは常に許可されています)、このスレッドの checkAccess メソッドが呼び出され、SecurityException がスローされる可能性があります。

このスレッドが Object クラスの wait()、wait(long)、または wait(long, int) メソッド、または join()、join(long)、join(long, int) の呼び出しでブロックされている場合、sleep(long)、または sleep(long, int)、このクラスのメソッドの場合、その割り込みステータスはクリアされ、InterruptedException を受け取ります。

このスレッドが割り込み可能なチャネルでの I/O 操作でブロックされた場合、チャネルは閉じられ、スレッドの割り込みステータスが設定され、スレッドは ClosedByInterruptException を受け取ります。

このスレッドがセレクターでブロックされている場合、スレッドの割り込みステータスが設定され、セレクターのウェイクアップ メソッドが呼び出されたかのように、スレッドは選択操作からすぐに戻ります。おそらくゼロ以外の値になります。

前の条件のいずれも保持されない場合、このスレッドの割り込みステータスが設定されます。

生きていないスレッドを中断しても、何の効果もありません。

例外: SecurityException - 現在のスレッドがこのスレッドを変更できない場合

結論として; cancel ofFutureTaskは、スレッドがブロックされている場合にのみ影響します (wait() の呼び出しで...)。それ以外の場合はThread.currentThread().isInterrupted()、終了を確認するのは開発者の責任です。ブロックされていない操作を実行している間。

于 2016-05-12T11:13:56.227 に答える