嵌入式ActiveMQ Artemis通过JMX创建Address/Divert时阻塞问题
嵌入式ActiveMQ Artemis JMX创建Address死锁问题解决
问题根源分析
死锁的核心逻辑是循环锁等待:
beforeCreateQueue钩子运行在持有PostOfficeImpl对象锁的Broker主线程中- 此时发起JMX的
createAddress/createDivert操作,RMI线程会尝试再次获取PostOfficeImpl锁(地址创建需要修改路由表,必须持有该锁) - 最终形成:Broker主线程持锁等JMX返回,RMI线程等锁被Broker主线程释放的死锁
直接解决方案(绕过死锁)
方案1:异步执行地址创建
避免在同步钩子中发起修改类JMX调用,改用异步线程执行:
@Override public boolean beforeCreateQueue(QueueConfiguration queueConfig, boolean autoCreateAddress, Map<String, Object> options) throws Exception { if (!broker.getPostOffice().addressExists(queueConfig.getAddress())) { // 用Broker内置线程池或自定义线程池异步执行 broker.getExecutorFactory().getExecutor().submit(() -> { try { ManagementService managementService = broker.getManagementService(); managementService.createAddress(queueConfig.getAddress(), RoutingType.MULTICAST, false); } catch (Exception e) { // 自行处理异常日志 } }); } return true; }
方案2:直接调用Broker本地API替代JMX
跳过JMX的跨线程调用,直接用Broker内部API创建地址,避免锁竞争:
@Override public boolean beforeCreateQueue(QueueConfiguration queueConfig, boolean autoCreateAddress, Map<String, Object> options) throws Exception { if (!broker.getPostOffice().addressExists(queueConfig.getAddress())) { AddressInfo addressInfo = new AddressInfo(queueConfig.getAddress(), RoutingType.MULTICAST); // 直接调用PostOffice本地方法创建地址 broker.getPostOffice().addAddress(addressInfo, false); } return true; }
嵌入式权限配置修正
嵌入式环境下,代码配置优先级高于XML,需直接通过代码设置权限:
Configuration config = new ConfigurationImpl(); // 禁用安全(如果不需要权限控制) config.setSecurityEnabled(false); // 若需启用安全,直接在代码中配置角色权限 Map<String, Set<String>> securityRoles = new HashMap<>(); securityRoles.put("createAddress", Collections.singleton("admin")); config.putSecurityRoles(securityRoles); // 初始化启动Broker ActiveMQServer server = ActiveMQServers.newActiveMQServer(config); server.start();
验证步骤
- 启动嵌入式Broker后,用MQTT客户端连接现有地址
- 触发队列创建逻辑(如客户端订阅新队列)
- 通过VisualVM检查线程状态,确认无BLOCKED状态的RMI线程
- 验证目标地址是否成功创建
内容的提问来源于stack exchange,提问作者TdBm
相关产品推荐
相关产品推荐

