spring 中的多线程
Multithreading in spring
我正在尝试进入 spring 多线程,我有几个问题。
我在 ThreadRating class 中有可运行的方法。现在我不确定使用它的最佳方式。
选项 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>
这是我的问题:
- 这两个选项有什么区别吗?速度、内存、可能的泄漏?或者它们只是写法不同?
- 使用网络服务时需要关闭池吗?我知道在第二个选项中我不需要,但是使用 webservice 时是否相同?
- 当使用第二个选项时 - 我应该如何指示等待所有作业完成?在第一个选项中,我只是关闭池并等待完成。但在第二个选项中,代码请求在任务完成之前完成。
executor.execute(worker);
- 只是为了澄清。这实际上并不是在创建一个新线程,而是将任务添加到队列中,如果队列已满,它会在代码的这一行等待直到有空闲位置?
感谢您帮助我理解。
主要区别:在选项 1) 中,您在每个
updateRating()
调用,在选项 2 中)执行器在部署时创建一次
时间,你给同一个执行者提供新的工作。第二种方法要好得多。
为什么要关闭执行器? 正在创建新的执行者
并关闭它们以等待任务处理完毕是反模式。请记住,创建 执行程序是为了控制系统资源 并且应该这样对待。 (例如,您有 50 个连接的数据库连接池——因此,为了服务于数据库访问,您创建了 50 个线程的执行程序——以避免超过连接限制。或者您在服务器上有 24 个核心,需要以最佳方式并行工作) .
而且,正如我在评论中提到的,在某些环境(例如应用程序服务器)中,您通常无权关闭执行程序。这样的尝试将产生 SecurityException
.
如果你需要等到工人完成他们的工作,用Callable
而不是Runnable
包装每个工作,然后从主线程调用相应的future.get()
-它会阻止
直到工作完成。支持超时。 Example
完全正确。线程由执行者自己创建和销毁,当它认为是最好的时候。尝试使用 jvisualvm 监控您的应用,看看它是如何发生的。
1.) 选项 1 实施不当,因为您在本地定义执行程序服务并在每次使用后关闭它。这违背了创建线程池的目的——它需要是一个全局对象,所以选项 2 是可行的方法。
2.)调用web服务时不需要关闭executor服务。如果 web 服务没有响应,调用最终将超时,线程将完成执行。如果您关闭执行程序服务,它将无法用于下一次调用。
3.) 如果您在线程结束后需要某种形式的通知,则应改用 Callable in conjuction with Futures。
4.) 您的执行程序服务最多分配了 10 个线程,它不会产生比这些线程更多的线程。如果它们都忙,您的任务将空闲,直到其中一个线程可用。
我正在尝试进入 spring 多线程,我有几个问题。
我在 ThreadRating class 中有可运行的方法。现在我不确定使用它的最佳方式。
选项 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>
这是我的问题:
- 这两个选项有什么区别吗?速度、内存、可能的泄漏?或者它们只是写法不同?
- 使用网络服务时需要关闭池吗?我知道在第二个选项中我不需要,但是使用 webservice 时是否相同?
- 当使用第二个选项时 - 我应该如何指示等待所有作业完成?在第一个选项中,我只是关闭池并等待完成。但在第二个选项中,代码请求在任务完成之前完成。
executor.execute(worker);
- 只是为了澄清。这实际上并不是在创建一个新线程,而是将任务添加到队列中,如果队列已满,它会在代码的这一行等待直到有空闲位置?
感谢您帮助我理解。
主要区别:在选项 1) 中,您在每个
updateRating()
调用,在选项 2 中)执行器在部署时创建一次 时间,你给同一个执行者提供新的工作。第二种方法要好得多。为什么要关闭执行器? 正在创建新的执行者 并关闭它们以等待任务处理完毕是反模式。请记住,创建 执行程序是为了控制系统资源 并且应该这样对待。 (例如,您有 50 个连接的数据库连接池——因此,为了服务于数据库访问,您创建了 50 个线程的执行程序——以避免超过连接限制。或者您在服务器上有 24 个核心,需要以最佳方式并行工作) .
而且,正如我在评论中提到的,在某些环境(例如应用程序服务器)中,您通常无权关闭执行程序。这样的尝试将产生
SecurityException
.如果你需要等到工人完成他们的工作,用
Callable
而不是Runnable
包装每个工作,然后从主线程调用相应的future.get()
-它会阻止 直到工作完成。支持超时。 Example完全正确。线程由执行者自己创建和销毁,当它认为是最好的时候。尝试使用 jvisualvm 监控您的应用,看看它是如何发生的。
1.) 选项 1 实施不当,因为您在本地定义执行程序服务并在每次使用后关闭它。这违背了创建线程池的目的——它需要是一个全局对象,所以选项 2 是可行的方法。
2.)调用web服务时不需要关闭executor服务。如果 web 服务没有响应,调用最终将超时,线程将完成执行。如果您关闭执行程序服务,它将无法用于下一次调用。
3.) 如果您在线程结束后需要某种形式的通知,则应改用 Callable in conjuction with Futures。
4.) 您的执行程序服务最多分配了 10 个线程,它不会产生比这些线程更多的线程。如果它们都忙,您的任务将空闲,直到其中一个线程可用。