ExecutorServiceののできない割り込みタスク

Themelis:

編集:

私が作成したJavaアプリケーションを作成したAndroidの環境のこの問題の外側をテストするにはExecutorService、タスクの提供AttackScript(同じクラス)をして終了します。

これは予想通り100%の作品、スレッドが中断され、タスクが停止しています。

あなたも、そのことにより、タスクをキャンセルする必要はありませんFuture.cancel(true)ExecutorService.shutdownNow()仕事をしていません。Androidの中に何かがあるServiceというスレッドプールで何とか台無しに?

expceptedとして動作するコード:

public static void main(String[] args) {
        AttackScript script = new AttackScript("http://ninjaflex.com/");

        ExecutorService executor = Executors.newFixedThreadPool(5);
        executor.submit(script);
        executor.submit(script);
        executor.submit(script);
        executor.submit(script);

        sleep(1300);

        // Automatically interrupts threads in the pool.
        executor.shutdownNow();
    }

    private static void sleep(long timeMilli){
        try {
            Thread.sleep(timeMilli);
        } catch(Exception e) {
            System.out.println("Error sleep()");
        }
    }

オリジナルのポスト:

私はAndroidの持っているService、それが含まれるExecutorServiceいくつかのタスクを実行する責任がフィールドを、。

タスクは、対象となるAttackScriptクラス。私はキャッシュFutureで参照をMap<String,Future>、私は後でそれらを取り消すことができるようになりますように、タスクと呼ばれ、。

Future future = executor.submit(new AttackScript(attack.getWebsite()));
tasks.put(attack.getPushId(), future);

ServiceさんonDestroy()(ユーザが通知ボタンを押したときに呼ばれる)私はすべてのタスクをキャンセル

private void cancelAllTasks() {
    for (Map.Entry<String, Future> futureEntry : tasks.entrySet()) {
        futureEntry.getValue().cancel(true);
    }
}

その後、シャットダウンエグゼキュータ

private void shutdownThreadPool() {
     // https://www.baeldung.com/java-executor-service-tutorial
     executor.shutdown();
     try {
         if (executor.awaitTermination(800, TimeUnit.MILLISECONDS))
                executor.shutdownNow();
     } catch (InterruptedException e) {
            executor.shutdownNow();
     }
}

最後にここにあるAttackScriptのクラスは:

public class AttackScript implements Runnable {
    private static final String TAG = "AttackScript";
    private URL url;

    public AttackScript(String website) {
        initializeUrl(website);
    }

    private void initializeUrl(String website) {
        try {
            url = new URL(website);
        } catch (MalformedURLException e) {
            Log.e(TAG, "Wrong url?", e);
        }
    }

    @Override
    public void run() {
        while (!Thread.currentThread().isInterrupted()) {
            readUrl();
        }
        Log.d(TAG, "Stopped requesting from " + url + " server.");
    }

    private void readUrl() {
        InputStream in = null;
        try {
            in = url.openStream();
        } catch (IOException e) {
            Log.e(TAG, "openStream() error.", e);
        } finally {
            closeInputStream(in);
        }
    }

    private void closeInputStream(InputStream in) {
        try {
            in.close();
            Log.d(TAG, "InputStream closed for " + url);
        } catch (IOException e) {
            Log.e(TAG, "Error while closing the input stream.", e);
        }
    }
}

奇妙な部分はほとんど、10のうち1のように、作業が中断されていないことで、AttackScript実行が停止さん。しかし、他の9つのタスクが上)(openStreamsに続けて、中断されていなかったURLの。

ジョージ・マリガン:

あなたはこの問題を回避するために、有効な回避策をすでに答えが、私は原因を説明します。障害がでないですExecutorServiceが、スレッドの割り込みステータスがネットワークライブラリで静かにクリアされた状態で。

あなたと他のコメンターが発見したように、これは非常によく、使用している特定のデバイスとそのAndroidのバージョンによって異なりますができます。

アンドロイド4.4のようOkHttpに使用されますHttpUrlConnection各スレッドが中断しているか否かであるときとの間に競合状態があるInputStream古いバージョンで閉じられていたが。

一環としてclose()呼び出し、このコードは、最終的に実行されます。

public void throwIfReached() throws IOException {
    if (Thread.interrupted()) {
        throw new InterruptedIOException("thread interrupted");
    }

    if (hasDeadline && deadlineNanoTime - System.nanoTime() <= 0) {
        throw new InterruptedIOException("deadline reached");
    }
}

あなたは、に基づいて見ることができThread.interrupted()、それは、スレッドの割り込みステータスをクリアし、決してそれを再度設定しますコール。

問題を作るためにあなたが代わりに頼ることができるように悪いに見えますInterruptedIOExceptionが、あなたがそれを処理する機会を持っていないので、ストリームを閉じるときに黙って内部的に処理されています。

の最新バージョンを使用している場合、あなたのコードサンプルは、私のために働きましたOkHttpそれ以降のバージョンではより多くの注意が割り込みステータスを維持するために取られたように見えますし、予想通りそれが実際に動作します。

しかし、歴史的に割り込みがとうまく再生されないように見えるの検索いくつかに基づいてOkHttp、彼らはお勧めの要求を停止するCall.cancel()可能性を代わりに。

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=138335&siteId=1