原因

最近在完善公司的基础发布平台的时候,使用到了一线程去做一些异步的事情,在开发环境和测试环境验证没有任何问题,但是在程序在生产运行一段时间后,发现没有得到自己想要的结果,为此开始了漫长的排查bug的之路,因为用到了一些线程,但是实际又没有对这些线程足够的监控,所以在排查问题的时候也是历经艰难险阻;

原始代码


protected ScheduledExecutorService executorService = Executors.newScheduledThreadPool(2);

/**
* 同步应用的jenkins状态
*/
public void threadASyncAppJenkinsStatus() {
executorService.scheduleAtFixedRate(() -> {
List<ArchitectureApp> architectureApps = architectureAppMapper.listArchitectureApp();
architectureApps.parallelStream().forEach(architectureApp -> syncJenkinsBuild(architectureApp.getName(), ArchitectureType.APP)); }, 0, 6, TimeUnit.SECONDS); } /**
* 同步组件的jenkins状态
*/
public void syncComponentJenkinsStatus() {
executorService.scheduleAtFixedRate(() -> {
List<ArchitectureComponent> architectureComponents = architectureComponentMapper.listArchitectureComponent();
architectureComponents.parallelStream().forEach(architectureComponent -> syncJenkinsBuild(architectureComponent.getName(), ArchitectureType.COMPONENT));
}, 0, 6, TimeUnit.SECONDS); }
 

这是其中一部分的代码,做的事情很简单,程序每隔6s就去轮询组件和应用的状态,然后后面我会通过websocket同步到前端页面。这是一段很简单的代码,很难想象这段代码可能出错。但是事与愿违,通过开发和测试环境的测试,在上到生产运行了两天发现前端页面的jenkins状态并没有同步。而通过查看日志,也没法观察问题出在哪,所以只能另寻他法;

ExecutorsMonitor线程监控类

以下是我们开发的一个线程池工具类,该工具类扩展ScheduledThreadPoolExecutor实现了线程池监控功能,能实时将线程池使用信息打印到日志中,方便我们进行问题排查、系统调优。具体代码如下

@Slf4j
class ExecutorsMonitor extends ScheduledThreadPoolExecutor { private ConcurrentHashMap<String, Date> startTimes;
private String poolName; /**
* 调用父类的构造方法,并初始化HashMap和线程池名称
*
* @param corePoolSize 线程池核心线程数
* @param poolName 线程池名称
*/
public ExecutorsMonitor(int corePoolSize, String poolName) {
super(corePoolSize);
this.startTimes = new ConcurrentHashMap<>();
this.poolName = poolName;
} /**
* 线程池延迟关闭时(等待线程池里的任务都执行完毕),统计线程池情况
*/
@Override
public void shutdown() {
super.shutdown();
} /**
* 线程池立即关闭时,统计线程池情况
*/
@Override
public List<Runnable> shutdownNow() {
return super.shutdownNow();
} /**
* 任务执行之前,记录任务开始时间
*/
@Override
protected void beforeExecute(Thread t, Runnable r) {
startTimes.put(String.valueOf(r.hashCode()), new Date());
} /**
* 任务执行之后,计算任务结束时间
*/
@Override
protected void afterExecute(Runnable r, Throwable t) {
Date startDate = startTimes.remove(String.valueOf(r.hashCode()));
Date finishDate = new Date();
long diff = finishDate.getTime() - startDate.getTime();
// 统计任务耗时、初始线程数、核心线程数、正在执行的任务数量、已完成任务数量、任务总数、队列里缓存的任务数量、池中存在的最大线程数、最大允许的线程数、线程空闲时间、线程池是否关闭、线程池是否终止
log.info(String.format(this.poolName
+ "-pool-monitor: Duration: %d ms, PoolSize: %d, CorePoolSize: %d, Active: %d, Completed: %d, Task: %d, Queue: %d, LargestPoolSize: %d, MaximumPoolSize: %d, KeepAliveTime: %d, isShutdown: %s, isTerminated: %s",
diff, this.getPoolSize(), this.getCorePoolSize(), this.getActiveCount(), this.getCompletedTaskCount(), this.getTaskCount(),
this.getQueue().size(), this.getLargestPoolSize(), this.getMaximumPoolSize(), this.getKeepAliveTime(TimeUnit.MILLISECONDS),
this.isShutdown(), this.isTerminated()));
} public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize, String poolName) {
return new ExecutorsMonitor(corePoolSize, poolName);
} }

  

后来在生产终于定位问题,发现线程内部后来停止,同时发现的还有报错,通过查阅资料发现,原来线程发生异常后会退出,通过try catch很好的解决了这个问题

java线程池监控的更多相关文章

  1. 干货 | 教你如何监控 Java 线程池运行状态

    之前写过一篇 Java 线程池的使用介绍文章<线程池全面解析>,全面介绍了什么是线程池.线程池核心类.线程池工作流程.线程池分类.拒绝策略.及如何提交与关闭线程池等. 但在实际开发过程中, ...

  2. 干货:教你如何监控 Java 线程池运行状态

    之前写过一篇 Java 线程池的使用介绍文章<线程池全面解析>,全面介绍了什么是线程池.线程池核心类.线程池工作流程.线程池分类.拒绝策略.及如何提交与关闭线程池等. 但在实际开发过程中, ...

  3. Java并发(六)线程池监控

    目录 一.线程池监控参数 二.线程池监控类 三.注意事项 在上一篇博文中,我们介绍了线程池的基本原理和使用方法.了解了基本概念之后,我们可以使用 Executors 类创建线程池来执行大量的任务,使用 ...

  4. java线程池

    http://cuisuqiang.iteye.com/blog/2019372 Java四种线程池的使用 java线程线程池监控 Java通过Executors提供四种线程池,分别为:newCach ...

  5. (转载)JAVA线程池管理

    平时的开发中线程是个少不了的东西,比如tomcat里的servlet就是线程,没有线程我们如何提供多用户访问呢?不过很多刚开始接触线程的开发攻城师却在这个上面吃了不少苦头.怎么做一套简便的线程开发模式 ...

  6. 基于 JVMTI 实现 Java 线程的监控(转)

    随着多核 CPU 的日益普及,越来越多的 Java 应用程序使用多线程并行计算来充分发挥整个系统的性能.多线程的使用也给应用程序开发人员带来了巨大的挑战,不正确地使用多线程可能造成线程死锁或资源竞争, ...

  7. 这么说吧,java线程池的实现原理其实很简单

    好处 : 线程是稀缺资源,如果被无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,合理的使用线程池对线程进行统一分配.调优和监控,有以下好处: 1.降低资源消耗: 2.提高响应速度: 3.提高线 ...

  8. 【java线程系列】java线程系列之java线程池详解

    一线程池的概念及为何需要线程池: 我们知道当我们自己创建一个线程时如果该线程执行完任务后就进入死亡状态,这样如果我们需要在次使用一个线程时得重新创建一个线程,但是线程的创建是要付出一定的代价的,如果在 ...

  9. Java 线程池(ThreadPoolExecutor)原理分析与使用

    在我们的开发中"池"的概念并不罕见,有数据库连接池.线程池.对象池.常量池等等.下面我们主要针对线程池来一步一步揭开线程池的面纱. 使用线程池的好处 1.降低资源消耗 可以重复利用 ...

随机推荐

  1. idea中git回退远程仓库版本

    工作中遇到,代码已提交并已提交到远程仓库,现需要回退到之前版本,记录如下: 记录当前版本的版本号和需要回退到版本的版本号. current version:85e7f32dfe421c5892a4e2 ...

  2. Map-Amap:自定义地图

    ylbtech-Map-Amap:自定义地图 1.返回顶部 1. http://lbs.amap.com/getting-started/mapstyle 2. 2.返回顶部 1. 自定义地图,地图从 ...

  3. 15. Jmeter-配置元件二

    jmeter-配置元件介绍与使用 JDBC Connection Configuration Java请求默认值 密钥库配置 LDAP Extended Request Defaults LDAP请求 ...

  4. haskell基本语法

    定义新类型 data EmployeeInfo = Employee Int String String [String] deriving(Read, Show, Eq, Ord) Employee ...

  5. select的限制与poll的使用

    select的限制 select的并发数受到两个限制:1.一个进程能打开的最大描述符数量;2.select中fd_set集合容量的限制(FD_SETSIZE) 关于进程的最大描述符数量: ulimit ...

  6. ABAP字符串处理

    字符串中包含单引号:单引号前面再加一个单引号 例:jest~stat = 'E0002' jest~stat = 'E0003' OR jest~stat = 'E0004' IF z_stat IS ...

  7. JavaScript Set

    function Set() { var items = {}; this.has = function(value) { return value in items } this.add = fun ...

  8. 常用缓存淘汰算法(LFU、LRU、ARC、FIFO、MRU)

    缓存算法是指令的一个明细表,用于决定缓存系统中哪些数据应该被删去. 常见类型包括LFU.LRU.ARC.FIFO.MRU. 最不经常使用算法(LFU): 这个缓存算法使用一个计数器来记录条目被访问的频 ...

  9. C++标准库的初探

    1,操作符 << 的原生意义是按位左移,例: 1 << 2; 其底层的意义是将整数 1 按位左移 2 位,即: 0000 0001  ==> 0000 0100: 2,重 ...

  10. js中获取input中所输入的值

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...