【问题标题】:How can I interrupt a Jsoup get thread before the timeout?如何在超时之前中断 Jsoup 获取线程?
【发布时间】:2017-03-24 18:17:49
【问题描述】:

我有这个问题: 我正在使用 Jsoup.connect(url).get() 从多个 url 获取 android asynctask 中的一些数据,然后在 Activity 中显示它。问题是有时我需要在获取 jsoup 结果或捕获超时异常之前中断线程并释放处理器。

代码的重要部分如下所示:

    @Override
    protected Void doInBackground(String... urls) {
            int cpuCount = Runtime.getRuntime().availableProcessors();

            BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();
            ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                    cpuCount,
                    cpuCount,
                    30,
                    TimeUnit.SECONDS,
                    queue);

            final CountDownLatch countDownLatch = new CountDownLatch(urls.length);

            for (final String url : urls) {
                threadPoolExecutor.execute(new Runnable() {
                    @Override
                    public void run() {
                        String html = null;
                        try {
                            html = Jsoup.connect(url).get().outerHtml();
                        } catch (Exception ignored) {
                        }

                        if (html != null) {
                            publishProgress(videoStream);
                        }
                        countDownLatch.countDown();
                    }
                });
            }
        countDownLatch.await();
        return null;
    }

    @Override
    protected void onProgressUpdate(String... result) {
        updateUiStuff(result[0]);
    }

我使用线程池执行器的原因是它并行执行多个线程中的连接,而不是等待一个结果并打开第二个连接等等。

我尝试在 onPreExecute 中设置的按钮上执行 cancel(true);threadPoolExecutor.shutDown();threadPoolExecutor.shutDownNow();,但它并没有停止 Runnables。即使我关闭活动,Runnables 也会继续运行,直到它们超时,直到那时我无法在网络上做任何事情,因为 jsoup 连接仍在运行。请指出我正确的方向。非常感谢,如果这是一个非常愚蠢的问题,我深表歉意,但我在这里找不到类似的问题。

简而言之:我需要在 AsyncTask 取消时停止线程。

【问题讨论】:

    标签: java android multithreading android-asynctask jsoup


    【解决方案1】:

    ThreadPoolExecutor 是一个通用的执行器,需要一些经验来配置。对于那些Executors 类中其他工厂方法返回的执行程序返回的执行程序,它是那些经验丰富的程序员的门户。此类构造函数之一的 Javadoc 甚至记录了它:

    使用{@link Executors} 工厂之一可能更方便 方法而不是这个通用的构造函数。

    您确定您仍想使用ThreadPoolExector?请注意,您始终可以向Executors 的方法提供ThreadFactory,以创建运行异步任务的实际线程。你不必去ThreadPoolExecutor

    在上面的调用中,您让每个线程等待 30 秒 (keepAliveTime),这使得它在终止前空闲等待。你确定要那个吗?

    您也只使用Runnable 实例作为您的任务。如果您考虑改用Callable 实例,则可以使用submit 方法,该方法返回可以取消的Future。这也有助于使用invokeAll() 方法,该方法允许您传入Callables 的集合并查询/取消返回的Futures。你上面说过你做了cancel(true),但请注意,该方法仅适用于Future

    关闭执行器或执行器服务的可靠方法是:

    • 使用shutdown() 方法将其关闭以尝试有序关闭。
    • 等待其终止。
    • 仅在需要时,现在使用 shutdownNow() 方法将其关闭,如果这样做,请正确处理返回的 Runnables 列表。
    • 处理好异常(需要强调)。我确信Jsoup.connect 会引发各种不同的异常,您应该正确处理它们。在您的情况下,可悲的是,您甚至将异常变量命名为ignored!请不要相信您在互联网上阅读的所有内容;)。

    通过这种方式获得ExecutorService 的一些经验后,您可以继续使用CompletionService,它在异步任务完成时提供Futures。这可以更好地利用并行性,尤其是在任务包含可变 IO 绑定活动的情况下。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-12-31
      • 1970-01-01
      • 2014-02-03
      • 1970-01-01
      • 2017-01-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多