JAvaスレッドプールモニタリング

4451 ワード

の原因となる
最近会社の基礎発表プラットフォームを完備する時、1つのスレッドを使っていくつかの非同期の事をして、開発環境とテスト環境の検証に何の問題もありませんが、プログラムが生産運行してしばらくの間、自分の望む結果が得られていないことを発見して、これのために長いバグの道を調査して、いくつかのスレッドを使ったため、しかし、実際にはこれらのスレッドを十分に監視していないので、問題を調査する際にも困難な障害を経験しています.
 
元のコード
 
  

protected ScheduledExecutorService executorService = Executors.newScheduledThreadPool(2);


/**
* jenkins
*/
public void threadASyncAppJenkinsStatus() {
executorService.scheduleAtFixedRate(() -> {
List architectureApps = architectureAppMapper.listArchitectureApp();
architectureApps.parallelStream().forEach(architectureApp -> syncJenkinsBuild(architectureApp.getName(), ArchitectureType.APP));

}, 0, 6, TimeUnit.SECONDS);

}

/**
* jenkins
*/
public void syncComponentJenkinsStatus() {
executorService.scheduleAtFixedRate(() -> {
List architectureComponents = architectureComponentMapper.listArchitectureComponent();
architectureComponents.parallelStream().forEach(architectureComponent -> syncJenkinsBuild(architectureComponent.getName(), ArchitectureType.COMPONENT));
}, 0, 6, TimeUnit.SECONDS);

}
 

これは一部のコードで、簡単なことをして、プログラムは6 sおきにコンポーネントとアプリケーションの状態をポーリングして、それから後でwebsocketを通じてフロントエンドページに同期します.これは簡単なコードで、このコードが間違っている可能性があるとは想像しにくい.しかし、予想に反して、開発とテスト環境のテストを通じて、生産まで2日間実行したところ、フロントエンドページのjenkins状態が同期していないことが分かった.ログを見ることで、問題がどこにあるかを観察することができないので、別の方法を探すしかありません.
 
ExecutorsMonitorスレッド監視クラス
スレッドプールの監視機能を実現し、リアルタイムでスレッドプールの使用情報をログに印刷することができ、問題のトラブルシューティング、システムのチューニングを容易にするスレッドプールツールクラスを開発しました.具体的なコードは以下の通りです.
@Slf4j
class ExecutorsMonitor extends ScheduledThreadPoolExecutor {


    private ConcurrentHashMap 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 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を通じてこの問題をよく解決した.