Springboot 项目 开启多线程
请参考 Spring Boot 对多线程支持-提高程序执行效率 \
Spring Boot 2.x多线程--使用@Async开启多线程使用示例
1.在Springboot项目中开启多线程支持
import java.util.concurrent.Executor;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@Configuration
@EnableAsync
public class ThreadConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(20);//核心线程数目
executor.setMaxPoolSize(Integer.MAX_VALUE);//最大线程数目
executor.setQueueCapacity(20);//队列中最大的数目
executor.initialize();
return executor;
}
}
2.在application.properties 配置Hikari 可以省略,不是必须
# Hikari will use the above plus the following to setup connection pooling
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.hikari.minimum-idle=20
spring.datasource.hikari.maximum-pool-size=600
#30min 此属性控制允许连接在池中闲置的最长时间,此设置仅适用于minimumIdle设置为小于maximumPoolSize的情况 默认:600000(10minutes)
spring.datasource.hikari.idle-timeout=180000
spring.datasource.hikari.auto-commit=true
spring.datasource.hikari.pool-name=DatebookHikariCP
#20min 一个连接的生命时长(毫秒),超时而且没被使用则被释放(retired),缺省:30分钟,建议设置比数据库超时时长少30秒
spring.datasource.hikari.max-lifetime=1200000
#10min 等待连接池分配连接的最大时长(毫秒),超过这个时长还没可用的连接则发生SQLException, 缺省:30秒
spring.datasource.hikari.connection-timeout=600000
spring.datasource.hikari.connection-test-query=SELECT 1 from dual
3.在需要开启多线程的方法或类上使用@Async注解 为方法或类开启线程
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@Service
public class AsyncTaskService {
@Async
public void executeAsyncTask(int i) {
System.out.println("线程" + Thread.currentThread().getName() + " 执行异步任务:" + i);
}
}
4.测试多线程 异步方法和调用方法一定要写在不同的类中
,如果写在一个类中,是没有效果的!
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class AsyncTaskServiceTest {
@Autowired
private AsyncTaskService asyncTaskService;
@Test
void testExecuteAsyncTask() {
for (int i = 0; i < 8; i++) {
asyncTaskService.executeAsyncTask(i);
}
}
}
5.运行测试方法,测试多线程。右键testExecuteAsyncTask()方法,Run As -> JUnit Test 启动项目,控制台输出如下:
6.线程池的排队和拒绝策略也很重要
请参考线程池排队策略和拒绝策略
解决java.util.concurrent.RejectedExecutionException
如果在一个方法里a 调用了 异步方法b 和 同步方法c 和 同步方法d。
那么它的执行顺序就是 b方法新开一个线程去执行。新线程执行b的同时,主线程会去顺序执行c和d。
对多线程,异步的一丢丢自己的理解。不保证对……
- 异步方法:异步方法 就是这个方法里的 操作会开多个线程同时执行。异步方法就是在方法还没执行完 它就可以返回。是吗?是的。如果有一个循环,且循环里的操作是互相不依赖的。就可以把 循环里的操作抽成一个方法,为这个方法 开启新线程。
- 同步方法:这个方法 及其所调用的方法 都在一个线程里执行,并且按先后顺序执行,这就是同步方法。如果一件事情 包括3个步骤,并且这3个步骤 都完成,才能把这件事的标志位置为完成状态。那么这件事就要写成一个同步方法。也就是说 这个方法 及其所调用的方法 都在一个线程里完成。
假设业务场景:
我们维护了一个账户集合,这个账户集合里有1000个账户。需要为每一个账户 去做报表,其中报表包括 主账户报表 和 该账户的子账户报表。
如果同步完成这个业务需求,1.我们可能会写一个方法generateReportForOne(),这个方法实现的功能是为每一个账户去生成它的主账户报表和子账户报表。2.然后再写一个方法 generateReport() ,去循环账户集合,然后调用 generateReportForOne()方法为所有的账户去生成报表。3. 也就是说它的执行流程是: 为账户1做完报表,再为账户2去做报表,再为账户3去做报表……为账户1000去做报表。这就是同步方法,所有的事情 都在一个线程里去完成。效率太低。我们可能
如果采用异步方法呢?因为各个账户之间生成报表是独立的,并不互相依赖。也就是说:为账户1做报表 和 为账户2做报表 互相是独立的,并不依赖。所以可以采用异步方法来执行这个业务操作。
1.把为一个账户生成报表 的方法 generateReportForOne() 开启一个新线程。2.然后在 generateReport()方法中for循环所有的账户,去调用生成报表的方法 generateReportForOne()。3.这样呢 各个账户 生成报表的操作是在独立的线程里面完成的。 可以同时为很多很多个账户生成报表,会极大地提高效率。。。。从15分钟缩短到1分钟。