【问题标题】:How to call same function in parallel with executor service in JAVA?如何在 JAVA 中与执行器服务并行调用相同的函数?
【发布时间】:2022-01-19 12:02:19
【问题描述】:

我是 Java 并发和线程的新手,我有以下场景 -

Function1(从队列中获取下一个任务并使用任务调用 function2)然后 Function2(调用 Function Run 来运行这个任务)然后 运行(函数运行是使用具有固定线程池的执行器服务提交任务,代码如下)

    ExecutorService exeService = Executors.newFixedThreadPool(3);
         private void run(Task task){
                    Abstract batchExecutor = getBatchExecutor(param1,param2, param3, param4, task);
                    Future<Void> future = exeService.submit(batchExecutor);
                    while (!future.isDone()) {
                        if (isStopRequested.get()) {
                            try {
                                future.get(5, TimeUnit.MINUTES);
                                } catch (TimeoutException e) {
                            e.printStackTrace();
                        }
                        throw new InterruptedException("message");
                    }
                            Thread.sleep(3000);
                    }
                        future.get();
                   Map<String, Result> submittedObjects = batchExecutor.getSubmittedObjects();
                   storeSubmittedObjects(submittedObjects);
        }

我的问题是,即使在声明了线程池之后,任务仍在按顺序运行。我怎样才能让它并行,以便一旦有另一个运行调用它应该使用池中的空闲线程并提交任务?

所有这些函数都没有返回类型。

【问题讨论】:

    标签: java multithreading concurrency executorservice parallelism-amdahl


    【解决方案1】:

    run(Task task) 方法末尾包含future.get();:这意味着您当前的线程将阻塞,直到提交的操作完成。因此,如果您在同一线程中对 run(Task task) 进行 3 次调用,则所有 3 个任务将按顺序执行而不是并行执行。

    如何正确处理这个问题取决于您如何构建应用程序。如果您不提交大量任务,则可以从该方法返回未来:

    private Future<Void> run(Runnable task){
        Abstract batchExecutor = getBatchExecutor(param1,param2, param3, param4, task);
        return exeService.submit(batchExecutor);
    }
    

    稍后再扫描结果:

    ArrayList<Future<Void>> pending = new ArrayList<>();
    pending.add(run(task1));
    pending.add(run(task2));
    pending.add(run(task3));
    // ...
    
    // clean up background tasks
    for (Future<?> fut : pending)
    {
        fut.get();
    }
    

    注意,如果你不使用未来的结果,你可以省略收集pending 和上面的循环。只需确保您的应用在所有任务完成后关闭执行程序队列即可:

    exeService.shutdown();
    exeService.awaitTermination(365, TimeUnit.DAYS);
    

    如果您需要在每个任务之后执行后期处理,您的run(Task) 方法应该更改为使用exeService.submit(Callable&lt;SomeResult - such as Abstract&gt;) 并返回Future&lt;SomeResult&gt;,以便您稍后可以在调用线程中执行后续操作。

    【讨论】:

    • 感谢您的回答,但在 future.get() 之后也使用抽象对象完成了一些计算。因此,返回未来对象在这里不起作用。 future.get() 也不会阻塞,因为已经有一个循环来检查未来是否完成。但我认为这也导致它按顺序运行。
    • 循环是问题的一部分,在future.get() 之后完全没有意义。两者都阻塞,直到任务完成,但您的循环可能比仅调用 future.get() 多花费 3 秒。只需让未来返回抽象对象,然后您就可以对其进行操作。
    猜你喜欢
    • 2016-11-21
    • 2015-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-11
    • 2014-08-22
    相关资源
    最近更新 更多