ActiveMQ 5.15.3线程池线程阻塞求助:阻塞于ensureConnectionInfoSent()及createSession
解决ActiveMQ 5.15.3线程阻塞在
ensureConnected的问题 看起来你遇到了ActiveMQ客户端线程大面积阻塞的棘手问题,我之前也处理过类似的情况,结合你给出的线程栈信息——大量messagePool线程卡在org.apache.activemq.ActiveMQConnection.ensureConnected(),咱们一步步拆解可能的原因和解决思路:
先搞懂为什么会阻塞在ensureConnected
ensureConnected()是ActiveMQ客户端用来确保和broker的连接处于可用状态的核心方法,调用createSession()时必然会触发这个检查。线程卡在这里,本质上是客户端在尝试建立/恢复连接时,要么拿不到内部锁,要么broker端迟迟不给响应。
可能的原因及对应的排查方案
1. 连接池配置和线程池不匹配
你用了PooledConnectionFactory,如果连接池的配置和业务线程池的规模不搭,很容易导致连接争抢:
- 连接池最大连接数太小:如果你的ThreadPoolExecutor线程数远大于
PooledConnectionFactory的maxConnections,大量线程会排队等连接,进而阻塞在连接池的锁或者连接建立逻辑上。- 先核对配置:看看
maxConnections是不是远小于线程池的核心/最大线程数,比如线程池开了30个线程,连接池却只给了10个连接,那肯定不够用。 - 调整参数:把
setMaxConnections()的值调到和线程池规模匹配,同时设置合理的idleTimeout,让闲置连接自动回收,避免资源浪费。
- 先核对配置:看看
- 连接池内部锁竞争:
PooledConnectionFactory的连接复用逻辑是加锁的,如果大量线程同时抢连接,锁等待会非常明显。- 可以试试开启
useExclusiveConnections(如果业务允许),让每个线程独占一个连接,减少锁竞争,但这会增加总连接数,得配合broker端的连接数限制一起调。
- 可以试试开启
2. ActiveMQ Broker端扛不住了
如果broker本身出问题,客户端会一直重试连接,自然会卡在ensureConnected:
- 连接数超限:ActiveMQ默认最大连接数是1000(通过
transportConnector的maxConnections配置),如果客户端连接数超过这个数,broker会拒绝新连接,客户端就会一直重试,导致阻塞。- 先查broker日志,搜搜有没有
Too many connections的错误,或者登录管理控制台(默认http://localhost:8161/admin)看当前连接数。 - 要么调大broker的
maxConnections,要么优化客户端连接池减少连接数。
- 先查broker日志,搜搜有没有
- broker线程池耗尽:broker有自己的线程池处理客户端请求,如果线程池满了,客户端的连接请求会被挂起。
- 看broker日志里有没有线程相关的警告,或者用JMX查看
org.apache.activemq:type=Broker,brokerName=localhost,connector=clientConnectors,connectorName=openwire下的线程指标。
- 看broker日志里有没有线程相关的警告,或者用JMX查看
- 网络波动:客户端和broker之间网络不稳定,连接频繁断连重连,
ensureConnected一直在尝试重建连接却失败。- 先测测网络连通性,比如ping、telnet看看有没有丢包或者延迟过高的情况。
- 可以在客户端加个配置
wireFormat.maxInactivityDurationInitalDelay,延长初始连接超时时间,避免过早触发重连逻辑。
3. 客户端代码有资源泄漏或线程不安全问题
虽然PooledConnectionFactory是线程安全的,但代码写得不对也会出问题:
- 没正确释放Session/Connection:如果线程拿了连接后,没在finally块里关闭Session、归还Connection(PooledConnectionFactory会自动回收连接,但Session必须手动关),会导致连接池里的连接被占死,其他线程拿不到连接就会阻塞。
- 检查代码,确保每次发完消息都在finally里关闭资源,比如这样:
Connection connection = null; Session session = null; MessageProducer producer = null; try { connection = pooledConnectionFactory.createConnection(); connection.start(); session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); Destination queue = session.createQueue("your-queue"); producer = session.createProducer(queue); // 发送消息逻辑 TextMessage msg = session.createTextMessage("test message"); producer.send(msg); } catch (JMSException e) { // 异常处理 } finally { // 倒序关闭资源 if (producer != null) try { producer.close(); } catch (Exception ignored) {} if (session != null) try { session.close(); } catch (Exception ignored) {} if (connection != null) try { connection.close(); } catch (Exception ignored) {} }
- 检查代码,确保每次发完消息都在finally里关闭资源,比如这样:
- 跨线程复用Session/Connection:如果多个线程共享同一个Session甚至Connection,会导致线程争抢Session的内部锁,进而卡在
createSession或者其他操作上。- 一定要保证每个线程独立获取Connection和Session,Session绝对不能跨线程用。
4. ActiveMQ 5.15.3的版本bug
5.15.3是比较老的版本了,可能存在一些连接池相关的已知bug:
- 比如某些场景下,连接池里的连接会变成无效状态,但没被及时回收,导致线程一直等无效连接。
- 能升级的话,尽量升到5.16.x或者更高的稳定版,很多老bug都被修复了。
- 暂时不能升级的话,把
PooledConnectionFactory的testOnBorrow设为true,每次拿连接时检查有效性,无效就重新创建。
快速排查优先级
- 先看broker日志,有没有连接数超限、线程池满这类明确的错误;
- 核对客户端连接池和线程池的配置,看看是不是连接数不够;
- 检查代码里的资源释放逻辑,有没有泄漏;
- 用Jstack/VisualVM看线程栈,确认是不是所有阻塞线程都在等同一个锁对象。
内容的提问来源于stack exchange,提问作者Sabya
相关产品推荐
相关产品推荐

