ExecutorService固定池线程挂起

5
我在我们的代码中使用以下代码片段。
ExecutorService executor = Executors.newFixedThreadPool(4);
while(loop 50 times){
    //In the extreme case I will have 50 threads and only 4 will be active and remaining are in queue 
    MyThread myThread = new MyThread();
    executor.execute(myThread);//Each Thread process 100,000 records and put in a file
}
executor.shutdown();
while (!executor.isTerminated()) {
}

以下是我的问题:

  1. 第二个while循环卡住了,可能的原因是什么?
  2. 有没有办法在一定时间间隔后终止整个线程池?
  3. 我能否在一定时间间隔后终止一个线程?

请帮我解决这个问题。


根据一些数据,我将决定迭代次数并在其中创建线程。如果需要更多信息,请告诉我。 - Java P
提供更加真实的代码。基于当前代码,我们无法确定问题是在循环中还是在你的Runnable任务中(假设MyThread是一个Runnable且命名非常糟糕)。 - Luiggi Mendoza
executor.shutdown()会允许已经计划的任务执行,但不会允许任何新任务,即使您已经启动了50个线程。在第二个while循环中有sleep吗?否则,这将占用大部分CPU,并且实际上可能导致正在执行的任务需要更长时间才能完成。 - Loganathan Mohanraj
你可以使用awaitTermination()来等待执行完成,而不是在while循环中检查终止状态。awaitTermination是阻塞调用,当执行完成时它会立即退出。 - Loganathan Mohanraj
@JavaP 只是好奇知道下面的答案是否解决了您的疑问? - Manjunath
2个回答

4

1.它在第二个while循环中卡住了,可能的原因是什么?

卡住的原因可能是线程数量太少,无法处理并存储需要处理并存储到文件中的记录数。如果每个线程应该处理100,000条记录并将其放入文件中,则由4个线程共享的50个线程任务将必须处理5,000,000条记录,并生成50个文件。因此最好增加线程数并检查。还要记下每个线程所花费的时间,以有效地衡量通过增加固定池线程的数量是否减少了总时间。

2.有没有办法在一定时间后终止整个线程池?

是的,下面的代码显示如何实现:

executor.shutdown();
executor.awaitTermination(60, TimeUnit.SECONDS); // blocks/waits for certain interval as specified
executor.shutdownNow(); // Forcefully terminate entire thread pool after the above time.

3.我能在一定时间间隔后终止一个线程吗?

是的,如果有效地终止线程的原因是停止它正在执行的任务。为了实现这一点,我们需要获取对未来的引用,并有条件地等待一段时间,然后强制取消任务并中断执行任务的线程。

        Map<String, Future> tasks = new HashMap<String, Future>();
        while(i++ < 50){
            //In the extreme case I will have 50 threads and only 4 will be active and remaining are in queue 
            Thread myThread = new Thread();
            tasks.put("Thread"+i ,executor.submit(myThread));//Each Thread process 100,000 records and put in a file
        }
        // say you want to terminate Thread2 after 60 seconds
        Future thread2Task = tasks.get("Thread2");
        thread2Task.get(60, TimeUnit.SECONDS);
        thread2Task.cancel(true); // boolean whether you want to interrupt the thred forcefully

这又是一个概率问题。所有提交给执行器的线程任务可能需要很长时间才能完成。最好计算一下任务完成所需的时间,这可以为我们提供最后一个 while 循环停止所需的时间指示。您实际上可以在最后一个 while 循环中睡眠几毫秒,以便它不会持续运行,并为执行器中的线程腾出空间来运行它们的任务。 - Manjunath
感谢您的关注。如果我在线程和线程池中都使用超时,只有一个按预期工作。它会等待线程超时直到所有线程完成,但当它到达线程池时,所有线程都已完成。因此,在线程池中指定超时没有任何用处。您有什么解决方案吗? - Java P
@JavaP 如我们所讨论的,我认为通过在 Future 上调用 get(2, TimeUnit.SECONDS),您将等待第一个线程 2 秒钟,然后在循环秒数之后,您将再等待 2 秒钟,以此类推,这将导致不同线程任务未能保持一致的等待时间。因此,理想的方法是在给定的时间段内等待执行器任务,这样可以给所有线程未来任务平等的机会,并按照上面回答的第二点调用 shutdownNow()。 - Manjunath
现在,如果一个线程的时间大约为2秒,并且由于有4个线程同时运行,最多可以进行50次迭代(线程任务),那么您可以计算等待终止时间为(迭代次数/4)* 2。这应该是您的大致awaitTermination时间(您可以再加上一两秒来考虑线程在并发环境中可能需要更长的时间运行)。如果您能够成功地在生产环境中实现,请告诉我们。 - Manjunath

1

ExecutorService将拥有一个线程池来执行您定义的Runnable任务,您定义了池的大小为4,我建议将其更改为机器上CPU的数量:

int threadCount = Runtime.getRuntime().availableProcessors();

ExecutorService executor = Executors.newFixedThreadPool(threadCount);

此外,似乎你正在发送线程给执行器以在其池中的一个可用线程中执行它们,这是多余的,你可以将MyThread更改为Runnable任务。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接