问题描述
(1)业务开发人员在启动项目时,会较高概率的出现cpu满载且一直无法停止的问题。任务管理器可以看到javaw.exe占用率为90%以上
(2)当启动项目时debug项目时,也会出现异常的卡顿,且能发现cpu占用率在稳步上升。
解决思路
1.尝试重现问题后,通过jvisualvm(jdk8中自带,后续版本被移除,但是可以兼容使用)工具观察堆、cpu运行的状态,能看出cpu是一直处于高负荷运行状态,且堆内存占用不大,GC线程也未占用cpu。可以判断是项目中部分线程一直在运行导致了cpu满载。
2.jps命令可以获取到当前运行的java进程号。通过比较cpu满载和jps列出的PID,可以确定满载的javaw.exe和Application为同一进程。
3.此时需要更进一步看到具体的线程占用情况,此时由于windows不能查看,需要下载对应的微软官方推荐的工具Process Explorer。
4.运行后选择对应的PID进程,右键点击选择Properties,可查看到对应的线程的TID。
5.在cpu发生满载现象时,执行命令jstack -l PID c:/*.stsck可获取到当前所有线程的状态。并在指定路径下生成了stack文件
6.此时获取到的TID为4位数字,通过win10自带的程序员计算器转换为16进制后在生成的stack文件中搜索线程即可。
7.此问题中定位到的线程如下,存在多个线程长期占用CPU且处于运行状态、
8.下面就是排查代码问题
发现当存在请求调用时,如果项目未启动则会导致此方法一直在自旋。
发生原因:
(1)由于liemsStarted变量未使用volatile关键字进行修饰,在多线程运行环境下,http线程并不能够及时的感知到此变量值已经改变。
(2)不加volatile会在编译时发生指令重排的优化,此代码可能会变成if(!liemsStarted){while(true){}}。
(3)while循环体中未执行任何代码,导致cpu无足够的间隔去重新获取liemsStarted的值,如果此处存在System.out.print,也可避免。
解决方案: