SpringBoot 线程池

配置文件

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ThreadPoolExecutor;
@Configuration
@EnableAsync
public class ThreadPoolTaskExecutorConfig {

    @Bean("testPool")
    public TaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 设置核心线程数
        executor.setCorePoolSize(5);
        // 设置最大线程数
        executor.setMaxPoolSize(10);
        // 设置队列容量
        executor.setQueueCapacity(20);
        // 设置线程活跃时间(秒)
        executor.setKeepAliveSeconds(60);
        // 设置默认线程名称
        executor.setThreadNamePrefix("hello-");
        // 设置拒绝策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 等待所有任务结束后再关闭线程池
        executor.setWaitForTasksToCompleteOnShutdown(true);
        return executor;
    }
}

模拟任务,假设每个任务大概需要耗时5S

@RestController
public class Test3Controller {


    @GetMapping("/test1")
    public void  test1() {
        test();
    }

    @Async("testPool")
    public void test() {
        SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
        try {
            Thread.sleep(5000);
            System.out.println("多线程异步执行" + Thread.currentThread().getName() + "  " + format.format(new Date()));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

启动类加入注解

@EnableAsync

我们可以使用jmeter对接口进行并发压力测试【安装教程:https://blog.csdn.net/weixin_44464726/article/details/86152691

当前线程池所能接受的最大任务数=最大线程数+队列容量

核心线程数=5

同时发送3个请求

结论:当线程池小于corePoolSize时,新提交任务将创建一个新线程执行任务,即使此时线程池中存在空闲线程。

同时发送8个请求

结论:.当线程池达到corePoolSize时,并且workQueue未满时,新提交任务将被放入workQueue中,等待线程池中任务调度执行

如配置所示,当前所配置的拒绝策略为:CallerRunsPolicy:

意思是:若当前请求超过最大任务数时,任务将被拒绝并将被直接在execute方法的调用线程中运行被拒绝的任务。

当前最大任务数为30,我给他同时发50个请求

可以看到有10个线程在我们自己定义的线程(线程名字为hello)上运行,超出最大线程数并且超出队列的20个线程直接在exec默认线程上运行了,5秒之后,10个线程任务运行完毕,从队列中获取任务去执行,知道队列中所有的任务都已经执行完成。

四种拒绝策略:

1、CallerRunsPolicy:让主线程去运行被抛弃掉的任务。好处是能够减缓新任务的提交速度。坏处是很有可能造成当前线程也被阻塞。如果所有线程都是不能执行的,很可能导致程序没法继续跑了。

2、AbortPolicy:jdk默认策略,策略直接抛出异常,丢弃任务。

3、DiscardPolicy:不能执行的任务将被删除,类似AbortPolicy,直接丢弃但不抛异常。

4、DiscardOldestPolicy:丢弃最早的未处理完的线程任务,然后获取下一个任务执行。

可自定义拒绝策略,参考:【https://blog.csdn.net/tanglei6636/article/details/90721801

自定义线程超时

任务:为了模拟实际程序中耗时,设置为随机睡眠时间

@Slf4j
@Component
public class Task {
    private static Random random = new Random();
    @Async("test1")
    public Future<String> run(String a) throws InterruptedException {
        long sleep = random.nextInt(4000);
        Thread.sleep(sleep);
        log.info("开始任务,需耗时:" + sleep + "毫秒");
        //设置默认返回值
        return new AsyncResult<>("test");
    }
}

调用该任务,若任务没有在2秒室内返回结果就会报超时异常,然后该任务被丢弃。


    @Autowired
    Task task;
    @GetMapping("test1")
    public String test1() throws Exception {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        Future<String> future = task.run("test");
        //2秒之内可以拿到结果就在2秒之内返回,超过2秒就会抛异常
        String s = future.get(2, TimeUnit.SECONDS);
        stopWatch.stop();
        System.out.println(stopWatch.prettyPrint());
        return s;
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Rorschach01

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值