springboot-集成线程池背景JDK原生方式sp

背景

以前写线程池都是使用JDK原生的自己写,线程安全自己来控制;springboot集成方式简化了使用配置,使用注解使方法异步化。我通过两种方式的对比来详细说明如何使用。

JDK原生方式

  • 代码如下
  • 阻塞队列是缓冲用的,可以提高吞吐量,用空间换时间,但是会有时间差,最终都会被执行,线程池本身也有一个队列,两个队列一起提高了缓冲长度
  • 休眠是控速用的
public class ThreadPoolTest {
    private static BlockingQueue<Thread> blockingQueue = new LinkedBlockingQueue(1000000);
    private static ExecutorService executorService = Executors.newCachedThreadPool();
    static {
        try {
            Thread t = blockingQueue.take();
            while (t != null) {
                System.out.println("do something!");
                executorService.submit(t);
                //控制取数速率
                Thread.sleep(100);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void addTask() {
        blockingQueue.add(new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("add a task!");
            }
        }));
    }
}
复制代码

springboot方式

  • 创建一个service层的接口AsyncService,如下:
public interface AsyncService {

    /**
     * 执行异步任务
     */
    void executeAsync();
}
复制代码
  • 对应的AsyncServiceImpl,实现如下:
@Service
public class AsyncServiceImpl implements AsyncService {

    private static final Logger logger = LoggerFactory.getLogger(AsyncServiceImpl.class);

    @Override
    public void executeAsync() {
        logger.info("start executeAsync");
        try{
            Thread.sleep(1000);
        }catch(Exception e){
            e.printStackTrace();
        }
        logger.info("end executeAsync");
    }
}
复制代码
  • 创建一个controller为Hello,里面定义一个http接口,做的事情是调用Service层的服务,如下:
@RestController
public class Hello {

    private static final Logger logger = LoggerFactory.getLogger(Hello.class);

    @Autowired
    private AsyncService asyncService;

    @RequestMapping("/")
    public String submit(){
        logger.info("start submit");

        //调用service层的任务
        asyncService.executeAsync();

        logger.info("end submit");

        return "success";
    }
}
复制代码
  • 创建一个配置类ExecutorConfig,用来定义如何创建一个ThreadPoolTaskExecutor,要使用@Configuration和@EnableAsync这两个注解,表示这是个配置类,并且是线程池的配置类,如下所示:
@Configuration
@EnableAsync
public class ExecutorConfig {

    private static final Logger logger = LoggerFactory.getLogger(ExecutorConfig.class);

    @Bean
    public Executor asyncServiceExecutor() {
        logger.info("start asyncServiceExecutor");
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //配置核心线程数
        executor.setCorePoolSize(5);
        //配置最大线程数
        executor.setMaxPoolSize(5);
        //配置队列大小
        executor.setQueueCapacity(99999);
        //配置线程池中的线程的名称前缀
        executor.setThreadNamePrefix("async-service-");

        //拒绝策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //执行初始化
        executor.initialize();
        return executor;
    }
}
复制代码
  • 将Service层的服务异步化: 打开AsyncServiceImpl.java,在executeAsync方法上增加注解@Async(“asyncServiceExecutor”),asyncServiceExecutor是前面ExecutorConfig.java中的方法名,表明executeAsync方法进入的线程池是asyncServiceExecutor方法创建的,如下:
@Override
    @Async("asyncServiceExecutor")
    public void executeAsync() {
        logger.info("start executeAsync");
        try{
            Thread.sleep(1000);
        }catch(Exception e){
            e.printStackTrace();
        }
        logger.info("end executeAsync");
    }
复制代码

总结

  • 我感觉只是书写形式发生了变化,本质上没有变化,原来怎么用现在还是怎么用
  • 还是推荐使用springboot的方式,代码风格上还是统一的
  • 这个跟阿里的规范不冲突