线程池系列(6)如何统一管理旧项目中的线程池
2022-03-11 本文已影响0人
小胖学编程
问题:在一个项目中,每一台机器活跃线程数有时候会有1000-2000个。当机器中存在大量无用的活跃线程时,便会影响性能,那么如何处理这种情况???
1. 问题
本文不讲述线程池是如何被统一管理的。重点描述:在旧已有项目中如何找到并管理已经存在的线程池。
项目中线程池的用法五花八门:
- 在类属性中声明JDK线程池;
- 使用
@Autowired
自动注入Spring的线程池; - 在一个公共工具类中声明多个JDK线程池,类的方法中直接使用线程池;
每个人编码风格不同,线程池的声明方式不同;每个人的对线程池的理解不同,所以核心参数的配置也就不同。导致了线程池的不可管理。
2. 解决方案
原理:借助于Spring的Bean的初始化流程+反射机制去解决这个问题。
项目在启动过程中,会将初始化Bean对象,此时会经过BeanPostProcessor
方法对bean进行代理增强处理(例如依赖BeanPostProcessor实现事务,依赖注入等)。
相关文章:
Spring进阶篇(5)- BeanPostProcessor(Bean的后置处理器)
Spring进阶篇(10)-BeanPostProcessor的注册时机
Spring进阶篇(9)- MethodValidationPostProcessor 后置处理器的运用
那么能否在初始化Bean时,通过反射技术来实现属性的增强?
2.1 引入相关依赖
引入反射相关依赖:
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.9.10</version>
</dependency>
引入TTL依赖:目的是它会重写线程池,来实现ThreadLocal跨线程参数传递(目的为了测试)
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId>
<version>2.11.5</version>
<scope>compile</scope>
</dependency>
JAVA进阶篇(8)—TransmittableThreadLocal—父子线程间线程本地变量
从TransmittableThreadLocal使用前调研(源码分析)
2.2 代码实现
实现代码:本段代码是一个思路,细节还需单独处理。
@Slf4j
@Component
public class ExtendExecutorsBeanPostProcessor implements BeanPostProcessor, PriorityOrdered {
private int order = Ordered.LOWEST_PRECEDENCE - 1;
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
//只处理本项目的bean
if(bean.getClass().getName().contains("com.tellme")) {
//反射得到的是ExecutorService、ThreadPoolExecutor的属性。
Set<Field> allFields =
ReflectionUtils.getFields(bean.getClass(),
i -> i != null && (i.getType().equals(ExecutorService.class) || i.getType()
.equals(ThreadPoolExecutor.class)));
allFields.stream().forEach(f -> {
f.setAccessible(true);
try {
//获取类中属性
ThreadPoolExecutor executorService = (ThreadPoolExecutor) f.get(bean);
//对原有线程池的装饰,使用到TTL线程池(此处不能是ThreadPoolExecutor类,否则会转换不过去)
ExecutorService ttlExecutorService =
TtlExecutors.getTtlExecutorService(executorService);
//替换
f.set(bean, ttlExecutorService);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
});
}
return bean;
}
@Override
public int getOrder() {
return this.order;
}
}
2.3 代码测试
@Slf4j
@RestController
public class ThreadLocalController {
private ExecutorService executorService = new ThreadPoolExecutor(1, 2,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
public static TransmittableThreadLocal<User> local = new TransmittableThreadLocal<>();
public static ThreadLocal<User> local2 = new ThreadLocal<>();
@RequestMapping("/local/t1")
public void t1(@RequestBody User user) {
//第一次使用线程池时前,创建多个ThreadLocal的值。
local.set(user);
local2.set(user);
System.out.println(executorService.getClass());
executorService.execute(() -> {
log.info("【/local/t1的add操作】子线程打印数据1:{}", local.get());
log.info("【/local/t1的add操作】子线程打印数据2:{}", local2.get());
});
}
@Data
@AllArgsConstructor
@NoArgsConstructor
private static class User{
private String id;
private String name;
}
}