我正在尝试进入 Spring 多线程,并且我有几个问题。

我在ThreadRating类中有可运行的方法。现在我不确定使用它的最佳方法。

选项1我发现:

private void updateRating() {
        ExecutorService executor = Executors.newFixedThreadPool(10);

    for (int i = 0; i < 10; i++) { // test
        // thread part
        Runnable worker = new ThreadRating(path, i, products.get(i), dao, fileHandler);
        executor.execute(worker);
    }
    executor.shutdown();
    try {
        executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
    } catch (InterruptedException e) {
        log.error("There was an error when ending threads");
        System.exit(1);
    }
    System.out.println("Finished all threads");
}

这似乎运行良好。在for循环之后,它等待直到线程完成并结束。

我尝试过的第二个选项
private TaskExecutor taskExecutor;

public UpdateBO(TaskExecutor taskExecutor) {
    this.taskExecutor = taskExecutor;
}

private void updateRating() {
        for (int i = 0; i < 10; i++) { // test
            Runnable worker = new ThreadRating(path, i, products.get(i), dao, fileHandler);
            taskExecutor.execute(worker);
        }
    // wait for threads to be finished before you go any further ??
        }

在xml文件中
<beans:bean id="taskExecutor"
    class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
    <beans:property name="corePoolSize" value="5" />
    <beans:property name="maxPoolSize" value="10" />
    <beans:property name="queueCapacity" value="25" />
    <beans:property name="waitForTasksToCompleteOnShutdown" value="true" />
</beans:bean>

<beans:bean id="updateBO" class="UpdateBO">
    <beans:constructor-arg ref="taskExecutor" />
</beans:bean>

这是我的问题:
  • 这两个选项之间有什么区别吗?速度,内存,可能的泄漏?还是他们只是用不同的方式写的一样?
  • 使用Web服务时是否需要关闭池?我知道在第二个选项中我不必这样做,但是使用Web服务时是否一样?
  • 使用第二个选项时-如何告诉我在那里等待所有作业完成?在第一个选项中,我只是关闭池并等待完成。但是在第二种选择中,代码请求在任务完成之前就完成了。
  • executor.execute(worker);-仅作澄清。这实际上不是在创建新线程,而是将任务添加到队列中,如果队列已满,它将在代码中的这一行上等待,直到有空闲空间为止?

  • 感谢您帮助我理解。

    最佳答案

  • 主要区别:在选项1)中,您将在每个updateRating()调用,在选项2中)执行程序在部署时创建一次
    时间,您为同一位执行者提供了新的工作。第二种方法要好得多。
  • 为什么需要关闭执行程序? 创建新的执行者
    并关闭它们以等待直到任务处理完毕为止是antipattern
    。请记住,创建执行程序是为了控制系统资源,应该这样对待。 (例如,您具有50个连接的数据库连接池-因此,要为数据库访问提供服务,您可以创建50个线程的执行程序-以避免超出连接限制。或者您在服务器上拥有24个核心,并且需要以最佳方式并行化工作) 。

    而且,正如我在评论中提到的那样,在某些环境(例如应用服务器)中,您通常无权关闭执行程序。这样的尝试将产生SecurityException
  • 如果您需要等到 worker 完成工作,则用Callable而不是Runnable包装每个作业,然后从主线程中调用相应的future.get()-它将阻塞
    直到工作完成。支持超时。 Example
  • 绝对正确。在认为最佳时机时,线程由执行器本身创建和销毁。尝试使用jvisualvm监视您的应用程序,以了解其发生情况。
  • 09-16 04:22