不能中断的ExecutorService的任务

问题描述 投票:8回答:2

编辑:

为了测试我创建了创建ExecutorService Java应用程序的Android环境之外这个问题,提供AttackScript(同一类)的任务,然后终止。

这将按预期100%,线程被中断,该任务被停止。

你甚至不用其Future.cancel(true)取消任务。 ExecutorService.shutdownNow()做这项工作。有什么在Android的Service不知何故与线程池食堂?

即按预期工作代码:

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类的对象。我缓存在FutureMap<String,Future>引用,称为任务,这样我以后可以取消它们。

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

Service'sonDestroy()(被称为当用户按下通知按钮),我取消所有任务

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);
        }
    }
}

怪异的是,很少,像1出10,任务中断和AttackScript的停止执行。但其他9个任务不中断,继续openStreams()上URLs。

java android executorservice interrupt-handling
2个回答
2
投票

你有一个有效的解决方法已经回答来避免这个问题,但我会解释原因。该故障是不符合ExecutorService但与线程的中断状态由网络图书馆静静地清除。

当你和另一个评论者发现这很可能取决于你所使用的特定设备和Android版本上。

由于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()如果可能的话,而不是一个请求。


4
投票

不得不寻找一个替代解决方案,我完全删除使用一个线程池,现在实现单点Threads,存储在Map

中断是,再次,从来没有发生这样的AtomicBoolean目前正在控制线程的执行。

private AtomicBoolean stopped = new AtomicBoolean(false);

 @Override
    public void run() {
        while (!stopped.get()) {
            readUrl();
        }
}

public void stopExecution() {
        stopped.set(true);
}

这是一个绝望的举动,但是,到目前为止,唯一可行的。

© www.soinside.com 2019 - 2024. All rights reserved.