Springboot下整合多线程 异步操作 查询数据库

pom.xml配置导入如下:

       <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

yml文件添加多线程核心配置

server:
  #端口号
  port: 8080
spring:
  task:
    pool:
      corePoolSize: 4
      maxPoolSize: 8
      keepAliveSeconds: 60
      queueCapacity: 20

corePoolSize不宜超过cpu核心数

创建线程池参数装载类:

@ConfigurationProperties(prefix = “spring.task.pool”)是让spring在创建bean时去加载配置文件中开头为spring.task.pool的内容,如果的配置文件位置不同的话可以引用别处。

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix = "spring.task.pool")
public class TaskThreadPoolConfig {
    private int corePoolSize;

    private int maxPoolSize;

    private int keepAliveSeconds;

    private int queueCapacity;

    public int getCorePoolSize() {
        return corePoolSize;
    }

    public void setCorePoolSize(int corePoolSize) {
        this.corePoolSize = corePoolSize;
    }

    public int getMaxPoolSize() {
        return maxPoolSize;
    }

    public void setMaxPoolSize(int maxPoolSize) {
        this.maxPoolSize = maxPoolSize;
    }

    public int getKeepAliveSeconds() {
        return keepAliveSeconds;
    }

    public void setKeepAliveSeconds(int keepAliveSeconds) {
        this.keepAliveSeconds = keepAliveSeconds;
    }

    public int getQueueCapacity() {
        return queueCapacity;
    }

    public void setQueueCapacity(int queueCapacity) {
        this.queueCapacity = queueCapacity;
    }
}

spring boot 启动类上加上注解:
@EnableConfigurationProperties({TaskThreadPoolConfig.class})
这个不能忘记,不然没法异步

@Configuration
@SpringBootApplication(scanBasePackages = "com",exclude = DataSourceAutoConfiguration.class)
@MapperScan(basePackages = "com.aistar.resources.mapper")
@EnableConfigurationProperties({TaskThreadPoolConfig.class})
public class LoginServiceApplication  {
    public static void main(String[] args) {
        SpringApplication.run(LoginServiceApplication.class, args);
    }
}

下面是一个简单demo使用方法:

测试类代码如下:

@SpringBootTest
class LoginServiceApplicationTests {

    @Autowired
    SysLoginUserService sysLoginUserService;
    @Autowired
    AsyncService asyncService;

    @Autowired
    SysParameterMapper sysParameterMapper;

    @Value("${config.jwt.secret}")
    private String secret;
    @Test
    void contextLoads() {
    }

    @Test
    public void test() throws ExecutionException, InterruptedException{
        long start = System.currentTimeMillis();
        Map<String, Object> map = new HashMap<>();
        List<Future<String>> futures = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            Future<String> future = asyncService.doReturn(i);
            futures.add(future);
        }
        List<String> response = new ArrayList<>();
        for (Future future : futures) {
            String string = (String) future.get();
            response.add(string);
        }
        map.put("data", response);
        map.put("消耗时间", String.format("任务执行成功,耗时{%s}毫秒", System.currentTimeMillis() - start));
        System.out.println(map);
    }

}

创建service层:

public interface AsyncService {
    Future<String> doReturn(int i);
    
     void doReturnNores(int i);
}

实现类:

@Service
public class AsyncServiceImpl implements AsyncService {
    @Async("taskAsyncPool")
    public Future<String> doReturn(int i){
        try {
            // 这个方法需要调用500毫秒
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 消息汇总
        return new AsyncResult<>(String.format("这个是第{%s}个异步调用的证书", i));
    }
    
   @Async("taskAsyncPool")
    public void doReturnNores(int i){
        try {
            // 这个方法需要调用500毫秒
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

执行结果:

  • {data=[这个是第{0}个异步调用的证书, 这个是第{1}个异步调用的证书, 这个是第{2}个异步调用的证书,
    这个是第{3}个异步调用的证书, 这个是第{4}个异步调用的证书, 这个是第{5}个异步调用的证书, 这个是第{6}个异步调用的证书,
    这个是第{7}个异步调用的证书, 这个是第{8}个异步调用的证书, 这个是第{9}个异步调用的证书, 这个是第{10}个异步调用的证书,
    这个是第{11}个异步调用的证书, 这个是第{12}个异步调用的证书, 这个是第{13}个异步调用的证书,
    这个是第{14}个异步调用的证书, 这个是第{15}个异步调用的证书, 这个是第{16}个异步调用的证书,
    这个是第{17}个异步调用的证书, 这个是第{18}个异步调用的证书, 这个是第{19}个异步调用的证书,
    这个是第{20}个异步调用的证书, 这个是第{21}个异步调用的证书, 这个是第{22}个异步调用的证书,
    这个是第{23}个异步调用的证书, 这个是第{24}个异步调用的证书, 这个是第{25}个异步调用的证书,
    这个是第{26}个异步调用的证书, 这个是第{27}个异步调用的证书, 这个是第{28}个异步调用的证书,
    这个是第{29}个异步调用的证书, 这个是第{30}个异步调用的证书, 这个是第{31}个异步调用的证书,
    这个是第{32}个异步调用的证书, 这个是第{33}个异步调用的证书, 这个是第{34}个异步调用的证书,
    这个是第{35}个异步调用的证书, 这个是第{36}个异步调用的证书, 这个是第{37}个异步调用的证书,
    这个是第{38}个异步调用的证书, 这个是第{39}个异步调用的证书, 这个是第{40}个异步调用的证书,
    这个是第{41}个异步调用的证书, 这个是第{42}个异步调用的证书, 这个是第{43}个异步调用的证书,
    这个是第{44}个异步调用的证书, 这个是第{45}个异步调用的证书, 这个是第{46}个异步调用的证书,
    这个是第{47}个异步调用的证书, 这个是第{48}个异步调用的证书, 这个是第{49}个异步调用的证书,
    这个是第{50}个异步调用的证书, 这个是第{51}个异步调用的证书, 这个是第{52}个异步调用的证书,
    这个是第{53}个异步调用的证书, 这个是第{54}个异步调用的证书, 这个是第{55}个异步调用的证书,
    这个是第{56}个异步调用的证书, 这个是第{57}个异步调用的证书, 这个是第{58}个异步调用的证书,
    这个是第{59}个异步调用的证书, 这个是第{60}个异步调用的证书, 这个是第{61}个异步调用的证书,
    这个是第{62}个异步调用的证书, 这个是第{63}个异步调用的证书, 这个是第{64}个异步调用的证书,
    这个是第{65}个异步调用的证书, 这个是第{66}个异步调用的证书, 这个是第{67}个异步调用的证书,
    这个是第{68}个异步调用的证书, 这个是第{69}个异步调用的证书, 这个是第{70}个异步调用的证书,
    这个是第{71}个异步调用的证书, 这个是第{72}个异步调用的证书, 这个是第{73}个异步调用的证书,
    这个是第{74}个异步调用的证书, 这个是第{75}个异步调用的证书, 这个是第{76}个异步调用的证书,
    这个是第{77}个异步调用的证书, 这个是第{78}个异步调用的证书, 这个是第{79}个异步调用的证书,
    这个是第{80}个异步调用的证书, 这个是第{81}个异步调用的证书, 这个是第{82}个异步调用的证书,
    这个是第{83}个异步调用的证书, 这个是第{84}个异步调用的证书, 这个是第{85}个异步调用的证书,
    这个是第{86}个异步调用的证书, 这个是第{87}个异步调用的证书, 这个是第{88}个异步调用的证书,
    这个是第{89}个异步调用的证书, 这个是第{90}个异步调用的证书, 这个是第{91}个异步调用的证书,
    这个是第{92}个异步调用的证书, 这个是第{93}个异步调用的证书, 这个是第{94}个异步调用的证书,
    这个是第{95}个异步调用的证书, 这个是第{96}个异步调用的证书, 这个是第{97}个异步调用的证书,
    这个是第{98}个异步调用的证书, 这个是第{99}个异步调用的证书], 消耗时间=任务执行成功,耗时{6014}毫秒}

每个线程500ms,100次执行结果下耗时6014,还算是ok的节约不少时间,我觉得还有优化空间。
如果是不需要返回结果的话可以执行下方这段test2,比如短信发送这类业务。
一般如果是并行查询数据的话应该都是要返回数据的,需要返回数据需要用Future<> 包裹,取得时候也是要先get出来,否则是没法阻塞的。

   @Test
    public void test2() throws ExecutionException, InterruptedException{
        long start = System.currentTimeMillis();
        Map<String, Object> map = new HashMap<>();
        List<Future<String>> futures = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            asyncService.doReturnNores(i);
        }
    }

以上就是全部教程了,学习犹如逆水行舟,不进则退。

参考文章:https://blog.csdn.net/u012480379/article/details/82899926

Spring Boot中,可以使用@Scheduled注解来实现定时任务,可以结合@Async注解来实现多线程异步。 首先,需要在启动类上添加@EnableAsync注解,开启异步支持。然后在要执行异步任务的方法上添加@Async注解。 接下来,可以使用Java中的Executor框架来创建线程池,用于执行异步任务。可以在应用程序中创建一个线程池,并使用@Async注解将任务提交给线程池执行。 下面是一个示例代码: ```java @Configuration @EnableAsync public class AsyncConfig { @Bean(name = "taskExecutor") public Executor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(10); executor.setMaxPoolSize(20); executor.setQueueCapacity(30); executor.setThreadNamePrefix("MyAsyncThread-"); executor.initialize(); return executor; } } @Service public class MyService { @Async("taskExecutor") @Scheduled(cron = "0 0 12 * * ?") //每天中午12点执行 public void myAsyncTask() { //异步任务内容 } } ``` 在上面的示例中,我们创建了一个名为“taskExecutor”的线程池,并将其注入到MyService中的myAsyncTask方法中。该方法使用@Async注解来指示它应该在异步线程中执行。@Scheduled注解指定了任务执行的时间。 需要注意的是,@Async注解只有在调用该方法的类通过Spring容器进行管理时才会生效。如果通过new关键字手动创建对象,@Async注解将不起作用。 希望这可以帮助你完成Spring Boot定时任务整合多线程异步的实现。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值