java 占用cpu过高_java 一次CPU占用过高问题的排查及解决

ps -mp 733 -o THREAD,tid,time | sort -rn

94e23190ddb7441e39f6586ba42b4c29.png

线程ID转换为16进制格式

printf "%x\n" 775

bf897d530912475dcc87c51d1005f02e.png

查看java  的堆栈信息

jstack 733 |grep 307 -A 30

ffb2b15b644b16a7c162e02ae332b1bd.png

640569d1f7a7133e4e1b6125ceb50dd8.png

显然是 SmsQueueServiceImpl 中的produceMissSms   和 consumeMissSms  方法有问题

一下为精简的部分代码

/**

* Created by dongxc on 2015/7/7. 通知消息队列

*/

@Service("smsQueueService")public classSmsQueueServiceImpl {//生产异常队列方法

public voidproduceMissSms(SmsLogDo smsLogDo) {/** try{ String key = EnumRedisPrefix.SMS_QUEUE_MISS_DEAL.getValue(); boolean result = redisService.lpush(key,

* smsLogDo, 0); if(result==false){ logger.error("通知消息异常队列生产消息返回失败!"+smsLogDo.getId()); } }catch(Exception e){

* logger.error("通知消息异常队列生产消息失败!", e); }*/}//消费异常队列方法

publicSmsLogDo consumeMissSms() {try{

String destKey=EnumRedisPrefix.SMS_QUEUE_MISS_DEAL.getValue();

SmsLogDo smsLogDo= newSmsLogDo();

Object obj= null;if (obj == null) {return null;

}else{

smsLogDo=(SmsLogDo) obj;

}returnsmsLogDo;

}catch(Exception e) {

logger.error("通知消息队列消费方法失败!", e);return null;

}

}

}

从很有年代感的垃圾代码来看  这两个方法并没有什么问题  继续往调用这两个方法的上层排查

/*** Created by dongxc on 2015/7/7.

* 消息通知监控线程*/@Service("smsMonitorComsumer")public classSmsMonitorComsumerImpl {

@AutowiredprivateSmsQueueServiceImpl smsQueueService;//取队列里的任务消费

@Transactional(propagation=Propagation.NOT_SUPPORTED)public voidrun() {while (true) {try{

SmsLogDo smsLogDo=smsQueueService.consumeMissSms();

Boolean result= false;if(smsLogDo!=null){long diff = (new Date()).getTime() -smsLogDo.getSendtime().getTime() ;long min = diff%(1000*24*60*60)%(1000*60*60)/(1000*60);//计算差多少分钟

if(min>5){

result= true;

}

}if(result){

smsQueueService.produceSms(smsLogDo);

}else{

smsQueueService.produceMissSms(smsLogDo);

}

}catch(Exception ex) {try{

Thread.sleep(3000);

}catch(Exception e){//logger.error("发送站内信息短信时线程执行失败2!", e);

}

}

}

}

}

很显然  这里有一个while(true)  无数个草泥马策马奔腾           ps:垃圾代码看多了, 我已经不愤怒了.

基本定位到问题了      while里面完全是没有用的代码

18382400723f5de57e617a27e292000b.png

继续往上层看谁来调用

/*** Created by dongxc on 2015/7/7.

* 通知消息队列*/@Service("smsLogRunThread")public classSmsLogRunThreadImpl {public intflag;

@AutowiredprivateSmsLogConsumerImpl smsLogConsumer;

@AutowiredprivateSmsMonitorComsumerImpl smsMonitorComsumer;

@PostConstructpublic voidinit() {if(ip!=""&&host!=""&&ip.equals(host)){

Thread thread= newThread(){public voidrun() {

smsLogConsumer.run();

}

};

thread.start();

Thread thread1= newThread(){public voidrun() {

smsMonitorComsumer.run();

}

};

thread1.start();

}

}

}

在应用一启动的时候   spring初始化的就会执行这一段处理丢失消息的代码   然后这段死循环代码  没有任何作用

解决方法   即   注释掉whlie(true)这一段代码

重新部署后 cpu占用就很正常了

9d0fa69d091efc3fca736bc1d747301f.png

案例一下,其实之前也遇到过CPU占用很高的问题,  但是那次是  频繁的GC导致的

其实排查问题 的过程中也是在不断的学习的过程 ! 先打个鸡血,我要继续搬砖了

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值