线程池使用不规范导致线程数大以及@Async的规范使用

文章详细内容来自:线程数突增!领导:谁再这么写就滚蛋!

下面是看完后文章的,一个总结

线程池的使用不规范,导致程序中线程数不下降,线程数量大。

临时变量的接口,通过下面简单的线程池执行,

java 复制代码
private static void threadDontGcDemo(){
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        executorService.submit(() -> {
            System.out.println("111");
        });
    }

线程不被GC回收,主要是线程池的gc root还是有可达路径的。这里讲个冷知识,这里的线程池的gc root是线程,具体的gc路径是thread->workers->线程池

如果临时采用线程池,需要 手动设置线程池的shutdown,下面写法:

java 复制代码
private static void threadDontGcDemo(){
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        executorService.submit(() -> {
            System.out.println("111");
        });
        executorService.shutdown();
    }

原理是,shutdown方法是遍历所有线程,并且调用线程的interrupt()方法,通知线程中断,当worker进行getTask()时,让处于wait的线程打断,抛出异常,workers捕获该worker,workers.remove(w),然后将worker移除workers,这样gc root就不可达了,便会被GC掉。

也就是说线程池的shutdownnow方法调用interruptIdleWorkers去对线程对象interrupt是为了让处于waiting或者是time_waiting的线程抛出异常。

总结为:

  • 线程池调用shutdownnow方法是为了调用worker对象的interrupt方法,来打断那些沉睡中的线程(waiting或者time_waiting状态),使其抛出异常

  • 线程池会把抛出异常的worker对象从workers集合中移除引用,此时被移除的worker对象因为没有到达gc root的路径已经可以被gc掉了

  • 等到workers对象空了,并且当前tomcat线程也结束,此时线程池对象也可以被gc掉,整个线程池对象成功释放

@Async 线程控制

如果不进行线程控制,则异步执行程序越多,会导致线程用尽。

一种方式是全局配置,所有的异步线程共用线程池

java 复制代码
@Configuration
public class AsyncConfig implements AsyncConfigurer {

  @Override
  public Executor getAsyncExecutor() {
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    executor.setCorePoolSize(10);
    executor.setMaxPoolSize(20);
    executor.setQueueCapacity(100);
    return executor;
  }

     @Override
  public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
    return new CustomAsyncExceptionHandler();
  }

    @Override
    public Integer getAsyncExecutor() {
      return 30; // 单位为秒
    }

}

另外一种是,@Async标签指定使用的线程池名称

java 复制代码
@Configuration
@EnableAsync
public class TaskExcutorConfig {
    @Bean("taskExecutor")
    public Executor taskExecutro() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setCorePoolSize(30);
        taskExecutor.setMaxPoolSize(50);
        taskExecutor.setQueueCapacity(200);
        taskExecutor.setKeepAliveSeconds(60);
        taskExecutor.setThreadNamePrefix("taskExecutor--");
        taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
        taskExecutor.setAwaitTerminationSeconds(60);
        return taskExecutor;
    }

    @Bean("commonExecutor")
    public Executor commonTaskExecutro() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setCorePoolSize(50);
        taskExecutor.setMaxPoolSize(100);
        taskExecutor.setQueueCapacity(2000);
        taskExecutor.setKeepAliveSeconds(60);
        taskExecutor.setThreadNamePrefix("commonExecutor--");
        taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
        taskExecutor.setAwaitTerminationSeconds(60);
        return taskExecutor;
    }

    @Bean("notificationExecutor")
    public Executor notificationExecutor() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setCorePoolSize(30);
        taskExecutor.setMaxPoolSize(60);
        taskExecutor.setQueueCapacity(2000);
        taskExecutor.setKeepAliveSeconds(60);
        taskExecutor.setThreadNamePrefix("notificationExecutor--");
        taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
        taskExecutor.setAwaitTerminationSeconds(60);
        return taskExecutor;
    }
}

使用时标明:

复制代码
@Async("commonExecutor")
相关推荐
东阳马生架构6 小时前
商品中心—6.商品考核系统的技术文档
java
晴空月明6 小时前
Java 内存模型与 Happens-Before 关系深度解析
java
皮皮林55110 小时前
SpringBoot 加载外部 Jar,实现功能按需扩展!
java·spring boot
rocksun10 小时前
认识Embabel:一个使用Java构建AI Agent的框架
java·人工智能
Java中文社群11 小时前
AI实战:一键生成数字人视频!
java·人工智能·后端
王中阳Go12 小时前
从超市收银到航空调度:贪心算法如何破解生活中的最优决策谜题?
java·后端·算法
shepherd11112 小时前
谈谈TransmittableThreadLocal实现原理和在日志收集记录系统上下文实战应用
java·后端·开源
维基框架12 小时前
Spring Boot 项目整合Spring Security 进行身份验证
java·架构
日月星辰Ace13 小时前
Java JVM 垃圾回收器(四):现代垃圾回收器 之 Shenandoah GC
java·jvm
天天摸鱼的java工程师13 小时前
商品详情页 QPS 达 10 万,如何设计缓存架构降低数据库压力?
java·后端·面试