文章详细内容来自:线程数突增!领导:谁再这么写就滚蛋!
下面是看完后文章的,一个总结
线程池的使用不规范,导致程序中线程数不下降,线程数量大。
临时变量的接口,通过下面简单的线程池执行,
- private static void threadDontGcDemo(){
- ExecutorService executorService = Executors.newFixedThreadPool(10);
- executorService.submit(() -> {
- System.out.println("111");
- });
- }
线程不被GC回收,主要是线程池的gc root还是有可达路径的。这里讲个冷知识,这里的线程池的gc root是线程,具体的gc路径是thread->workers->线程池
如果临时采用线程池,需要 手动设置线程池的shutdown,下面写法:
- 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 线程控制
如果不进行线程控制,则异步执行程序越多,会导致线程用尽。
一种方式是全局配置,所有的异步线程共用线程池
- @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标签指定使用的线程池名称
- @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")