由于环境中有部分服务器每天都会定时重新设置系统时间,ActiveMQ的连接常常出现僵死的情况。现象为Agent不再输出日志,根据现有日志判断线程卡在consumer.receive(60000)这一个语句上。今天下定决心研究了一下源码。
相关资料:http://m.blog.csdn.net/article/details?id=53501723
Agent在调用consumer.receive(60000)方法时,MQ内部的操作有一层是这样的(ActiveMQMessageConsumer.dequeue方法)
if ( timeout > 0) {
deadline = System. currentTimeMillis () + timeout ;
}
while ( true ) {
MessageDispatch md = unconsumedMessages .dequeue( timeout );
if ( md == null ) {
if ( timeout > 0 && ! unconsumedMessages .isClosed()) {
timeout = Math. max ( deadline - System. currentTimeMillis (), 0);
…………
当系统时间变化时(往前调整), System. currentTimeMillis 取到的时间会变小,最后一行的timeout会变大,导致等待时间增加,而且在 unconsumedMessages .dequeue( timeout ); 方法中,调用了如下的命令
while ( timeout != 0 && ! closed && ( list .isEmpty() || ! running )) {
if ( timeout == -1) {
mutex .wait();
} else {
mutex .wait( timeout );
break ;
}
}
mutex.wait(timeout),timeout为上一层中变大后的值,从而导致线程僵死,且不再接收消息,直到系统时间回复到(变化前的时间+60s)以后才能恢复正常。
解决方法是不在consumer.receive(timeout)中使用>0的timeout,由自己封装一层,每次调用consumer.receive(0),而后加一层逻辑判断系统时间是否有变化。
更进一步的解决方法是去官方提个bug。。。。。嗯,明天搞。。
网友评论