☆☆☆★☆☆☆

唯有努力才能活成自己想要活成的样子

导航

springboot中使用线程池记录

仅供自己记录

JDK自带的线程池ThreadPoolExecutor;

Spring默认也是自带了一个线程池方便我们开发,它是ThreadPoolTaskExecutor;

Spring更加推荐我们开发者使用ThreadPoolTaskExecutor类来创建线程池,其本质是对java.util.concurrent.ThreadPoolExecutor的包装;

一般使用自己配置的线程池,配置方式如下

在application.properties中配置:

#业务使用pool配置
thread.pool.name=pool_query-
thread.pool.max.size=8
thread.pool.core.size=5
thread.pool.queue.size=10
thread.pool.alive.time=5

 配置一个Config.java

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ThreadPoolExecutor;
/**
 * @Description 工作线程池
 */
@Configuration
public class ThreadExecutorPool {
    @Value("${thread.pool.max.size}")
    private Integer maxSize;
    @Value("${thread.pool.core.size}")
    private Integer coreSize;
    @Value("${thread.pool.queue.size}")
    private Integer queueSize;
    @Value("${thread.pool.alive.time}")
    private Integer aliveTime;
    @Value("${thread.pool.name}")
    private String threadPoolName;

    @Bean
    public ThreadPoolTaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(coreSize);//线程池维护线程的最少数量
        executor.setMaxPoolSize(maxSize);//线程池维护线程的最大数量
        executor.setQueueCapacity(queueSize);//缓存队列
        executor.setThreadNamePrefix(threadPoolName);
        executor.setKeepAliveSeconds(aliveTime);//允许的空闲时间
        // 该方法用来设置线程池关闭的时候 等待 所有任务都完成后,再继续 销毁 其他的 Bean,
        executor.setWaitForTasksToCompleteOnShutdown(true);
        // 任务的等待时间 如果超过这个时间还没有销毁就 强制销毁,以确保应用最后能够被关闭,而不是阻塞住。
        executor.setAwaitTerminationSeconds(300);
        //对拒绝task的处理策略
        //rejection-policy:当pool已经达到max size的时候,如何处理新任务
        //CALLER_RUNS:不在新线程中执行任务,而是由调用者所在的线程来执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }
}

常使用的两种方式

第一种:

在方法上添加@Async注解

stup1.在@SpringBootApplication启动类或者@Configuration注解类上 添加注解@EnableAsync启动多线程注解;

stup2.@Async这个方法开启异步多线程调用还需要将这个方法的类一定要交给Spring容器来管理(该方法写在另外一个类中,并且这个类使用到@Component注解)

关于注解失效需要注意以下几点

  1. 注解的方法必须是public方法
  2. 方法一定要从另一个类中调用,也就是从类的外部调用,类的内部调用是无效的,因为@Transactional和@Async注解的实现都是基于Spring的AOP,而AOP的实现是基于动态代理模式实现的。有可能因为调用方法的是对象本身而不是代理对象,因为没有经过Spring容器。
  3. 异步方法使用注解@Async的返回值只能为void或者Future

第二种:

使用线程池 threadPool直接执行相关业务:

无返回值的任务使用public void execute(Runnable command) 方法提交;

有返回值的任务使用public <T> Future<T> submit(Callable) 方法提交。

import com.txj.query.utils.AsyncTest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

/**
 * @description:
 */
@Slf4j
@RestController
@RequestMapping("/test")
public class Test {
    @Autowired
    private ThreadPoolTaskExecutor threadPool;
    @Autowired
    private AsyncTest asyncTest;

    @PostMapping("test")
    public void test() {
        List<String> list = Arrays.asList(new String[] {"1", "2", "3"});
        long start = System.currentTimeMillis();
        List<Future<String>> futures = new ArrayList<>();
        for (String sql : list) {
            System.out.println(sql+"开始执行:"+System.currentTimeMillis());
            //第一种方式
            Future<String> future1 = asyncTest.asyncTest("20220101", sql);
            //第二种方式
            Future<String> future2 = (Future<String>) threadPool.submit(new Thread(() -> {
                asyncTest("20220101", sql);
            }));//submit有返回值
            futures.add(future1);
            futures.add(future2);
        }
        List<String> response = new ArrayList<>();
        for (Future future : futures) {
            String string = null;
            try {
                string = (String) future.get();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } catch (ExecutionException e) {
                throw new RuntimeException(e);
            }
            response.add(string);
        }
        System.out.println(response);
        System.out.println( String.format("任务执行成功,耗时{%s}毫秒", System.currentTimeMillis() - start));
    }
public Future<String> asyncTest(String day, String sqls) { try { log.info(System.currentTimeMillis()+"开始执行,线程名称:{}", Thread.currentThread().getName()); Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } return new AsyncResult<>(String.format("这个是第{%s}个异步调用", sqls)); } }
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Component;
import java.util.concurrent.Future;

/**
 * @description:
 */
@Slf4j
@Component
public class AsyncTest {
    @Async("myExecutor")
    public Future<String> asyncTest(String day, String sqls) {
        try {
            log.info(System.currentTimeMillis()+"开始执行,线程名称:{}", Thread.currentThread().getName());
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return new AsyncResult<>(String.format("这个是第{%s}个异步调用", sqls));
    }
}

 

posted on 2023-03-10 14:27  Yr-Zhang  阅读(218)  评论(0编辑  收藏  举报