【问题标题】:Is it possible to wait the main thread while all the threads of executor service are processing tasks执行器服务的所有线程都在处理任务时是否可以等待主线程
【发布时间】:2020-02-15 14:44:30
【问题描述】:

我有一个将数百万数据插入后端的场景,目前正在使用执行器框架来加载它。我将用更简单的术语解释我的问题。

在以下情况下,我有 10 个可运行的线程和三个线程来执行相同的操作。考虑我的可运行对象正在执行插入操作,完成任务需要时间。当我检查时,了解到,如果所有线程都忙,其他任务将进入队列,一旦线程完成任务,它将从池中获取任务并完成它。

所以在这种情况下,SampleRunnable 4 到 10 的对象将被创建,这将在池中。

问题:由于我需要加载数百万个任务,我无法加载队列中的所有记录,这会导致内存问题。所以我的问题是,不是将所有任务都放在队列中,是否可以让主线程等待,直到任何一个执行器工作线程可用。

按照我尝试的解决方法而不是排队这么多任务:

方法 1:使用 Array Blocking Queue 作为 executor,大小为 5(例如) 所以在这种情况下,当第 9 个任务到来时,这将抛出 RejectedExecutionException 并在 catch 子句中,休眠 1 分钟并递归地尝试相同。当线程可用时,这将在任何重试时被拾取。

方法 2:使用关闭并等待终止。即如果任务计数为 5,我将关闭并等待终止。在 await Termination 'if' 块中(executor.awaitTermination(60000,TimeUnit.SECONDS)),我再次实例化线程池。


public class SampleMain {

public static void main(String[] args) {

ExecutorService executor = Executors.newFixedThreadPool(3);

for (int i=0;i<10;i++){ 
   executorService.execute(new SampleRunnable(i));
}

executor.shutdown();
}

【问题讨论】:

    标签: java multithreading executorservice


    【解决方案1】:

    听起来问题是,您想限制主线程,使其不会领先于工作线程。如果是这种情况,那么考虑显式构造一个ThreadPoolExecutor 实例而不是调用Executors.newFixedThreadPool()

    该类有几个不同的构造函数,其中大多数允许您提供自己的阻塞队列。如果你创建一个大小有限的ArrayBlockingQueue,那么每次队列满时,主线程都会自动阻塞,直到有一个worker通过另一个任务腾出空间。

    final int work_queue_size = 30;
    BlockingQueue work_queue = new ArrayBlockingQueue(work_queue_size);
    ExecutorService executor = new ThreadPoolExecutor(..., work_queue);
    
    for (int i=0;i<10;i++){ 
        executorService.execute(new SampleRunnable(i));
    }
    ...
    

    【讨论】:

    • 我在方法 1 上尝试了这个解决方案。在这种情况下,不是主线程被阻塞,而是抛出 RejectedExecutionException,即如果所有线程都忙并且队列已满。
    • final static BlockingQueue&lt;Runnable&gt; queue = new ArrayBlockingQueue&lt;&gt;(5); static ExecutorService executorService = new ThreadPoolExecutor(3, 3, 0L, TimeUnit.MILLISECONDS, queue); public static void main(String[] args) { for (int i=0;i&lt;10;i++){ executorService.execute(new SampleRunnable(i)); } executorService.shutdown(); } 。这是我尝试的代码 sn-p ,这将引发第 9 条记录的异常。
    • 糟糕!是的。我认为您还需要提供RejectedExecutionHandler。如果您为处理程序提供ThreadPoolExecutor.CallerRunsPolicy,那么您不应该得到异常,因为只要主线程尝试提交并且队列已满,就会在主线程上执行一个新任务。 (正如您可能知道的那样,我自己并没有这样做。我只是查看了文档,看看如果这是我的问题,我将如何解决问题。)
    • new ThreadPoolExecutor(3, 3, 0L, TimeUnit.MILLISECONDS,queue,new ThreadPoolExecutor.CallerRunsPolicy()); -- 在实例化执行器时添加了上述代码,这对我有用。即在这种情况下,线程池大小为 5,活动线程为 3。因此,当第 8 个任务到来时,它不会被执行,也不会填充异常。在那段时间里,主线程似乎也处于等待状态。如果是这种情况,我需要确定正确的池大小,我可以使用此解决方案来检查性能。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-08-18
    • 1970-01-01
    • 1970-01-01
    • 2019-10-24
    • 2014-05-10
    • 2019-10-08
    • 1970-01-01
    相关资源
    最近更新 更多