在一个分布式系统中,一般都会有一个或多个固定的线程池来处理我们提交的任务。很多时候我们需要关注线程池的运行情况,根据情况来调整我们线程池参数。我们可以使用Actuator 很简单的完成这件事情。
pom.xml
1 2 3 4 | <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> |
自定义一个监控线程池的 HealthContributor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | /** * @author lyy */ public class MyThreadPollHealthContributor implements HealthIndicator { private ThreadPoolExecutor executor; public MyThreadPollHealthContributor(ThreadPoolExecutor executor) { this.executor = executor; } @Override public Health health() { //核心线程数 int corePoolSize = executor.getCorePoolSize(); //活跃线程数 int activeCount = executor.getActiveCount(); //完成的任务数 long completedTaskCount = executor.getCompletedTaskCount(); //线程数历史高峰线 int largestPoolSize = executor.getLargestPoolSize(); //当前池中线程数 int poolSize = executor.getPoolSize(); BlockingQueue<Runnable> queue = executor.getQueue(); //队列剩余空间数 int remainingCapacity = queue.remainingCapacity(); //队列中的任务 int queueSize = queue.size(); //最大线程数 int maximumPoolSize = executor.getMaximumPoolSize(); //如果当前活跃线程数 大于 80%的最大线程数,就认证是down double rate = BigDecimal.valueOf(activeCount) .divide(BigDecimal.valueOf(maximumPoolSize), 2, BigDecimal.ROUND_HALF_UP) .doubleValue(); Map<String, Object> infoMap = new HashMap<String, Object>(); infoMap.put("核心线程数",corePoolSize); infoMap.put("当前活跃线程数", activeCount); infoMap.put("线程峰值", largestPoolSize); infoMap.put("完成的任务数", completedTaskCount); infoMap.put("当前池中线程数", poolSize); infoMap.put("队列剩余大小", remainingCapacity); infoMap.put("当前队列中的任务数", queueSize); infoMap.put("设置最大线程数", maximumPoolSize); if(rate > 0.8) { return Health.down().withDetails(infoMap).build(); }else { return Health.up().withDetails(infoMap).build(); } } |
我们可以监控多个对象,自定义一个 CompositeHealthContributor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | /** * @author lyy * 线程池 */ public class ThreadPoolConfig { public static final ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 1, TimeUnit.MINUTES, new ArrayBlockingQueue<Runnable>(100)); } /** * @author lyy */ @Component public class MyCompositeHealthContributor implements CompositeHealthContributor { private Map<String, HealthContributor> map = new HashMap<String, HealthContributor>(); @PostConstruct public void init() { MyThreadPollHealthContributor threadPool = new MyThreadPollHealthContributor(ThreadPoolConfig.executor); map.put("threadPoll", threadPool); addTask(); } @Override public HealthContributor getContributor(String name) { return map.get(name); } @Override public Iterator<NamedContributor<HealthContributor>> iterator() { List<NamedContributor<HealthContributor>> contributors = new ArrayList<NamedContributor<HealthContributor>>(); map.forEach((name,c) ->{ contributors.add(NamedContributor.of(name, c)); }); return contributors.iterator(); } /** * 模拟添加任务 */ public void addTask() { AtomicLong finishTaskNum = new AtomicLong(); new Thread(() ->{ while(true) { try { ThreadPoolConfig.executor.execute(() ->{ try { TimeUnit.SECONDS.sleep(ThreadLocalRandom.current().nextInt(10,40)); System.out.println("完成任务.."+ finishTaskNum.getAndIncrement()); } catch (Exception e) { e.printStackTrace(); } }); TimeUnit.SECONDS.sleep(1); } catch (Exception e2) { } } }).start(); } } |
application.yml
1 2 3 4 5 6 7 8 9 | management: endpoints: web: exposure: include: "*" endpoint: health: show-details: always |
ok,启动项目 访问 http://localhost:8080/actuator/health 就可以看到线程池的相关信息了