編集:
私が作成した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()
可能性を代わりに。