连接中断时调用JMSContext.close()阻塞问题求助
ActiveMQ Artemis客户端重连时close()阻塞问题的解决方法
问题描述
我有一个基于Java SE的ActiveMQ Artemis客户端应用,已在ActiveMQInitialContextFactory配置中设置reconnectAttempts=-1实现连接断开后自动重连,重连功能正常。但当连接处于断开重连状态时,调用JMSContext::stop()或JMSContext::close()会一直阻塞直到重连成功。若不调用这些方法直接停止应用,虽能正常退出(因使用守护线程),但该服务用于对话框场景,必须在关闭时释放占用的资源。
相关配置
java.naming.factory.initial=org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory connectionFactory.ConnectionFactory=tcp://192.168.0.1:1883?retryInterval=200&reconnectAttempts=-1
核心代码
ConnectionFactory cf = (ConnectionFactory) initialContext.lookup("ConnectionFactory"); JMSContext jmsContext = cf.createContext(); jmsContext.setExceptionListener(this::handleJMSException); Topic topic = jmsContext.createTopic("topicName"); jmsContext.createConsumer(topic).setMessageListener(this::onMessage); // 对话框关闭逻辑 setOnCloseRequest(dialogEvent -> { if(jmsContext != null) { jmsContext.close(); } });
解决方案
1. 主动终止重连尝试后关闭
直接操作底层ActiveMQ连接,先停止重连机制,再关闭JMSContext,避免阻塞:
setOnCloseRequest(dialogEvent -> { if(jmsContext != null) { try { // 转换为ActiveMQ专属JMSContext并获取底层连接 ActiveMQConnection connection = (ActiveMQConnection) ((ActiveMQJMSContext) jmsContext).getConnection(); // 停止重连尝试 connection.stop(); // 此时close()不会再阻塞 jmsContext.close(); } catch (JMSException e) { e.printStackTrace(); } } });
2. 修改连接配置取消阻塞
在连接URL中添加blockOnDurableSend=false参数,禁用持久化消息发送时的阻塞逻辑,从根源减少阻塞场景:
connectionFactory.ConnectionFactory=tcp://192.168.0.1:1883?retryInterval=200&reconnectAttempts=-1&blockOnDurableSend=false
3. 带超时的关闭线程
将close()操作放在单独线程中,设置超时时间,超时后强制中断线程,避免界面卡死:
setOnCloseRequest(dialogEvent -> { if(jmsContext != null) { Thread closeThread = new Thread(() -> { try { jmsContext.close(); } catch (Exception e) { Thread.currentThread().interrupt(); } }); closeThread.start(); // 设置3秒超时,可根据需求调整 try { closeThread.join(3000); if(closeThread.isAlive()) { closeThread.interrupt(); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } });
4. 监听连接状态优化关闭逻辑
通过异常监听器标记连接断开状态,关闭时针对性处理:
private boolean isConnectionLost = false; // 初始化时设置异常监听器 jmsContext.setExceptionListener(exception -> { handleJMSException(exception); isConnectionLost = true; }); // 对话框关闭逻辑 setOnCloseRequest(dialogEvent -> { if(jmsContext != null) { if(isConnectionLost) { try { ActiveMQConnection connection = (ActiveMQConnection) ((ActiveMQJMSContext) jmsContext).getConnection(); connection.stop(); } catch (JMSException e) { e.printStackTrace(); } } jmsContext.close(); } });
内容的提问来源于stack exchange,提问作者mr mcwolf
相关产品推荐
相关产品推荐

