【问题标题】:ExecutorService not terminating in timeExecutorService 没有及时终止
【发布时间】:2018-03-25 19:55:46
【问题描述】:

我有一个运行几个线程的 ExecutorService。

我想要完成的是执行,然后等待所有线程终止。为了给您提供更多背景信息,每个thread1 都连接到一个网站。

这是我想出的:

public static void terminateExecutor(ExecutorService taskExecutor) {

        taskExecutor.shutdown();
        try {
          taskExecutor.awaitTermination(2, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            System.out.println("Some tasks were interrupted!"); //This gets printed
        }
    }

现在,奇怪的是,使用 ExecutorService 的主线程终止了,但其中的 thread1s 没有。

我注意到这一点是因为thread1 抛出了一个错误(此时主线程已经死了)告诉我它没有找到指定的 URL(所以我猜它与连接有关)。

awaitTermination 是否有可能不会终止 thread1,因为它正在尝试(并且似乎在重试)连接到无效链接?

我无法以任何其他方式停止thread1(或者至少据我所知我不能),因为没有任何类型的循环。

编辑:

我通过创建一个新类并将其提供给执行程序得到thread1

for (....)
    {

        String urlToVisit = globalUrl + links.get(i);
        Thread thread1 = new MagicalThread(urlToVisit, 2).getThread();
        executor.execute(thread1);

    }
    terminateExecutor(executor.getExecutor());

【问题讨论】:

  • 1) thread1 在哪里? 2) 为什么要打印中断消息? 3) 我敢打赌你会发现awaitTermination's return value 告诉你一些相关的事情。
  • @AndyTurner thread1 从字面上连接到一个网站,如果抛出错误,它会打印“嘿,这个链接......不起作用!”。中断消息不应该被打印出来,以为有人可能会问它是否被打印,所以我添加了评论。
  • 请说明您如何获得“thread1”:您无法直接访问由ExecutorService 运行Runnable 的线程。也许你将它声明为Thread,但它实际上被用作Runnable,它是Thread 的事实并不相关,因为它运行在ExecutorService 的一个内部线程上。跨度>
  • ...MagicalThread 是如何声明的?如果你可以调用executor.executor()(看起来像ExecutorService),但调用terminateExecutor(executor.getExecutor())(看起来像 ExecutorService),那么executor 是什么。
  • @AndyTurner 好的,MagicalThread 实现了可运行,并且不是线程。我很快改变了它,尽管它仍然没有停止。是的,executor 是我创建的一个类,它使用 ExecutorService 来做他的事情。

标签: java multithreading


【解决方案1】:

来自Javadoc(强调我的):

阻塞直到所有任务完成执行在关闭请求之后

在调用awaitTermination之前需要先调用shutdown(),否则没有任何意义。

【讨论】:

  • 现在试过了。没有任何变化。
  • 在这种情况下,您需要提供有关当时正在运行的任务的更多详细信息。
【解决方案2】:

执行器使用中断来让线程知道是时候退出了。如果您的任务正在使用阻塞 I/O,那么它们将被阻塞并且无法检查中断标志。被阻塞的任务无法以睡眠或等待发生的方式响应中断,其中中断会导致线程唤醒并抛出 InterruptedException。

如果您在套接字上设置了超时,那么一旦套接字超时,任务就可以检查中断。您也可以通过关闭套接字让任务响应中断。见https://www.javaspecialists.eu/archive/Issue056.html

请注意,在线程池中实现这一点比链接文章中给出的示例涉及更多。除了运行之外,执行器的任何内容都不允许池调用任务上的方法。一种方法是将对套接字的引用放在 ThreadLocal 中。然后,您可以为池创建一个 ThreadFactory 以使用一个方法来子类化 Thread ,该方法覆盖线程上的中断方法以从 ThreadLocal 获取套接字并关闭它。

【讨论】:

  • 这是有道理的。我想知道为什么尝试连接的线程没有中断。尽管我重写了整个内容以使其正常工作,但这是正确的答案。谢谢
【解决方案3】:

什么时候

taskExecutor.awaitTermination(2, TimeUnit.SECONDS);

返回,它不保证ExecutorService 已经终止。看看它的return value

[返回] 如果此执行程序终止,则返回 true;如果在终止前超时,则返回 false

你不检查这个值,但我敢打赌,如果你在 ExecutorService 中运行的东西仍在运行,它会返回 false。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-08-17
    • 1970-01-01
    • 2022-10-24
    • 2015-01-11
    • 2011-06-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多