【自定义ThreadPoolTaskExecutor 来实现线程池模拟异步任务】

1、配置线程池

package com.lfsun.common.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ThreadPoolExecutor;


/**
 * 线程池参数优化
 *
 * @author Administrator
 */
@Configuration
public class ThreadPoolConfig {

    /**
     * defaultThreadPool 是一个通用线程池,适用于大部分情况;
     *
     * @return
     */
    @Bean(name = "defaultThreadPool")
    public ThreadPoolTaskExecutor defaultThreadPool() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(20); // 核心线程数
        executor.setMaxPoolSize(200); // 最大线程数
        executor.setQueueCapacity(100); // 队列容量
        executor.setKeepAliveSeconds(60); // 线程空闲后的最大存活时间
        executor.setThreadNamePrefix("defaultThreadPool-"); // 线程名称前缀
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); // 拒绝策略
        executor.initialize();
        return executor;
    }

    /**
     * customThreadPool 则是一个定制化的线程池,适用于特定的业务场景。
     *
     * @return
     */
    @Bean(name = "customThreadPool")
    public ThreadPoolTaskExecutor customThreadPool() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10); // 核心线程数
        executor.setMaxPoolSize(50); // 最大线程数
        executor.setQueueCapacity(10); // 队列容量
        executor.setKeepAliveSeconds(30); // 线程空闲后的最大存活时间
        executor.setThreadNamePrefix("customThreadPool-"); // 线程名称前缀
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy()); // 拒绝策略
        executor.initialize();
        return executor;
    }
}

2、定义接口(6个异步方法:3个无返回值,3个有返回值)

package com.lfsun.api.service;


import com.lfsun.common.result.GlobalJSONResult;
import java.util.concurrent.Future;

public interface AsyncService {

    void doTaskOne() throws Exception;

    void doTaskTwo() throws Exception;

    void doTaskThree() throws Exception;

    Future doTaskFour() throws Exception;

    Future doTaskFive() throws Exception;

    Future doTaskSix() throws Exception;
}

3、定义接口的实现类(都是sleep(1000)模拟执行任务,Stopwatch 用来计时)

package com.lfsun.service.main;

import com.google.common.base.Stopwatch;
import com.lfsun.api.service.AsyncService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class AsyncServiceImpl implements AsyncService {

    private static final Random RANDOM = new Random();

    @Autowired
    private Executor taskExecutor;

    @Async
    @Override
    public void doTaskOne() {
        log.info("开始做任务一");
        // 创建计时器
        Stopwatch stopwatch = Stopwatch.createStarted();
        try {
            Thread.sleep(1000);
            log.info("任务一 : {}", RANDOM.nextInt(100000));
        } catch (InterruptedException e) {
            log.error("任务一执行异常", e);
        }
        // 停止计时器
        stopwatch.stop();
        // 输出总耗时
        log.info("任务一完成,总耗时:{}毫秒", stopwatch.elapsed(TimeUnit.MILLISECONDS));
    }

    @Async
    @Override
    public void doTaskTwo() {
        log.info("开始做任务二");
        // 创建计时器
        Stopwatch stopwatch = Stopwatch.createStarted();
        try {
            Thread.sleep(1000);
            log.info("任务二 : {}", RANDOM.nextInt(100000));
        } catch (InterruptedException e) {
            log.error("任务二执行异常", e);
        }
        // 停止计时器
        stopwatch.stop();
        // 输出总耗时
        log.info("任务二完成,总耗时:{}毫秒", stopwatch.elapsed(TimeUnit.MILLISECONDS));
    }

    @Async
    @Override
    public void doTaskThree() {
        log.info("开始做任务三");
        // 创建计时器
        Stopwatch stopwatch = Stopwatch.createStarted();
        try {
            Thread.sleep(1000);
            log.info("任务三 : {}", RANDOM.nextInt(100000));
        } catch (InterruptedException e) {
            log.error("任务三执行异常", e);
        }
        // 停止计时器
        stopwatch.stop();
        // 输出总耗时
        log.info("任务三完成,总耗时:{}毫秒", stopwatch.elapsed(TimeUnit.MILLISECONDS));
    }

    @Async("taskExecutor")
    @Override
    public Future doTaskFour() {
        log.info("开始做任务四");
        // 创建计时器
        Stopwatch stopwatch = Stopwatch.createStarted();
        try {
            Thread.sleep(1000);
            log.info("任务四 : {}", RANDOM.nextInt(100000));
        } catch (InterruptedException e) {
            log.error("任务四执行异常", e);
        }
        // 停止计时器
        stopwatch.stop();
        // 输出总耗时
        log.info("任务四完成,总耗时:{}毫秒", stopwatch.elapsed(TimeUnit.MILLISECONDS));
        return CompletableFuture.completedFuture("4");
    }

    @Async("taskExecutor")
    @Override
    public Future doTaskFive() {
        log.info("开始做任务五");
        // 创建计时器
        Stopwatch stopwatch = Stopwatch.createStarted();
        try {
            Thread.sleep(1000);
            log.info("任务五 : {}", RANDOM.nextInt(100000));
        } catch (InterruptedException e) {
            log.error("任务五执行异常", e);
        }
        // 停止计时器
        stopwatch.stop();
        // 输出总耗时
        log.info("任务五完成,总耗时:{}毫秒", stopwatch.elapsed(TimeUnit.MILLISECONDS));
        return CompletableFuture.completedFuture("5");
    }

    @Async("taskExecutor")
    @Override
    public Future doTaskSix() {
        log.info("开始做任务六");
        // 创建计时器
        Stopwatch stopwatch = Stopwatch.createStarted();
        try {
            Thread.sleep(1000);
            log.info("任务六 : {}", RANDOM.nextInt(100000));
        } catch (InterruptedException e) {
            log.error("任务六执行异常", e);
        }
        // 停止计时器
        stopwatch.stop();
        // 输出总耗时
        log.info("任务六完成,总耗时:{}毫秒", stopwatch.elapsed(TimeUnit.MILLISECONDS));
        return CompletableFuture.completedFuture("6");
    }

    public void asyncPoolShutDown() {
        // 创建计时器
        Stopwatch stopwatch = Stopwatch.createStarted();
        List> futures = new ArrayList<>();
        for (int i = 0; i < 10000; i++) {
            futures.add(doTaskFour());
            futures.add(doTaskFive());
            futures.add(doTaskSix());
            log.info("这是第" + (i+1) + "次循环");
        }
        // 使用CompletableFuture.allOf方法等待所有异步任务完成,并在异步任务执行完毕后关闭线程池。
        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
                .whenComplete((result, error) -> {
                    taskExecutor.execute(() -> {
                        ((ThreadPoolTaskExecutor) taskExecutor).shutdown();
                        while (!((ThreadPoolTaskExecutor) taskExecutor).getThreadPoolExecutor().isTerminated()) {
                            //等待线程池关闭
                        }
                        // 停止计时器
                        stopwatch.stop();
                        // 输出总耗时
                        log.info("任务全部完成,总耗时:{}毫秒", stopwatch.elapsed(TimeUnit.MILLISECONDS));
                    });
                });
    }
}

4、定义控制层以访问接口

package com.lfsun.main.controller;

import com.google.common.base.Stopwatch;
import com.lfsun.api.service.AsyncService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

@Slf4j
@RestController
public class AsyncController {

    @Autowired
    private AsyncService asyncService;

    @Autowired
    private ThreadPoolTaskExecutor defaultThreadPool;

    /**
     * 不带返回值的异步调用
     */
    @GetMapping(value = "/asyncMethods")
    public void asyncMethods() throws Exception {
        // 创建计时器
        Stopwatch stopwatch = Stopwatch.createStarted();
        // 创建计数器
        CountDownLatch latch = new CountDownLatch(3);
        // 提交任务
        defaultThreadPool.submit(() -> {
            try {
                asyncService.doTaskOne();// 异步调用
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            latch.countDown();
        });
        defaultThreadPool.submit(() -> {
            try {
                asyncService.doTaskTwo();// 异步调用
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            latch.countDown();
        });
        defaultThreadPool.submit(() -> {
            try {
                asyncService.doTaskThree();// 异步调用
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            latch.countDown();
        });
        // 等待任务执行完成
        latch.await();
        // 停止计时器
        stopwatch.stop();
        // 输出总耗时
        log.info("任务全部完成,总耗时:{}毫秒", stopwatch.elapsed(TimeUnit.MILLISECONDS));
    }

    /**
     * 带返回值的异步调用
     */
    @GetMapping(value = "/asyncMethodsReturn")
    public void asyncMethodsReturn() {
        // 创建计时器
        Stopwatch stopwatch = Stopwatch.createStarted();
        // 创建 CompletableFuture 对象
        CompletableFuture> taskFour = CompletableFuture.supplyAsync(() -> {
            try {
                return asyncService.doTaskFour();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }, defaultThreadPool);
        CompletableFuture> taskFive = CompletableFuture.supplyAsync(() -> {
            try {
                return asyncService.doTaskFive();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }, defaultThreadPool);
        CompletableFuture> taskSix = CompletableFuture.supplyAsync(() -> {
            try {
                return asyncService.doTaskSix();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }, defaultThreadPool);
        // 等待所有任务执行完成
        CompletableFuture.allOf(taskFour, taskFive, taskSix).join();
        // 停止计时器
        stopwatch.stop();
        // 输出总耗时
        log.info("任务全部完成,总耗时:{}毫秒", stopwatch.elapsed(TimeUnit.MILLISECONDS));
    }

    /**
     * 关闭线程池
     */
    @GetMapping(value = "/asyncPoolShutDown")
    public void asyncPoolShutDown() {
        // 创建计时器
        Stopwatch stopwatch = Stopwatch.createStarted();
        // 提交任务
        for (int i = 0; i < 10; i++) {
            // 创建任务
            Runnable task = () -> {
                try {
                    asyncService.doTaskOne();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            };
            // 提交任务
            defaultThreadPool.execute(task);
            task = () -> {
                try {
                    asyncService.doTaskTwo();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            };
            defaultThreadPool.execute(task);
            task = () -> {
                try {
                    asyncService.doTaskThree();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            };
            defaultThreadPool.execute(task);
        }
        // 预启动核心线程
        defaultThreadPool.setPrestartAllCoreThreads(true);
        // 关闭线程池
        defaultThreadPool.shutdown();
        // 等待所有任务执行完成
        while (!defaultThreadPool.getThreadPoolExecutor().isTerminated()) {
            // 等待线程池中的任务全部完成
        }
        // 停止计时器
        stopwatch.stop();
        // 输出总耗时
        log.info("线程池已经关闭,总耗时:{}毫秒", stopwatch.elapsed(TimeUnit.MILLISECONDS));
    }
}

5、测试结果

5.1、 无返回值

http://localhost:8888/asyncMethods/
【自定义ThreadPoolTaskExecutor 来实现线程池模拟异步任务】_第1张图片
在这里插入图片描述

5.2、有返回值(有多余输出是因为我之前定义的切面,范围有些广,没有去改)

http://localhost:8888/asyncMethodsReturn/
【自定义ThreadPoolTaskExecutor 来实现线程池模拟异步任务】_第2张图片
在这里插入图片描述

5.3、关闭线程池(上面有java.lang.InterruptedException: sleep interrupted

,线程池关闭时候有未执行完线程就会报这种错 )
http://localhost:8888/asyncPoolShutDown/
【自定义ThreadPoolTaskExecutor 来实现线程池模拟异步任务】_第3张图片

5.4、再次关闭线程池(无报错)

你可能感兴趣的:(记录,多线程,Java,java,spring,spring,boot)