Многопоточный JMX-клиент

Я пытаюсь реализовать JMXclient для мониторинга удаленной JVM. Я получаю соединение mbeanserver из основного метода и передаю его потоку, который ищет использование памяти. Проблема в том, что когда я делаю это, я получаю сообщение об ошибке "Клиент был закрыт". Но если я запускаю программу без потоков, она работает отлично.

public class ESBMonitor {
     private static TreeSet<ObjectName> mbeansNames = null;

     public static void main(String[] args) throws IOException {
         RemoteConnector.defaultConnector();
         MBeanServerConnection remote = RemoteConnector.getRemote();
         //MemoryExtractor.getMemoryInfo();
         MemoryExtractor memoryExtractor = new MemoryExtractor();
         memoryExtractor.start();
         RemoteConnector.closeConnection();
     }
}



public class RemoteConnector {

private static MBeanServerConnection remote = null;
private static JMXConnector connector = null;
private static final Logger logger= LogManager.getLogger(RemoteConnector.class);

public static void defaultConnector() {
    try {
        JMXServiceURL target = new JMXServiceURL
                ("service:jmx:rmi://localhost:11111/jndi/rmi://localhost:9999/jmxrmi");
        //for passing credentials for password
        Map<String, String[]> env = new HashMap<String, String[]>();
        String[] credentials = {"admin", "admin"};
        env.put(JMXConnector.CREDENTIALS, credentials);

        connector = JMXConnectorFactory.connect(target, env);
        remote = connector.getMBeanServerConnection();
        logger.info("MbeanServer connection obtained");

    } catch (MalformedURLException e) {
        logger.error(e.getStackTrace());
    } catch (IOException e) {
        logger.error(e.getStackTrace());
    }
}

public static MBeanServerConnection getRemote() {
    return remote;
}



public static synchronized Object getMbeanAttribute(ObjectName bean, String attribute) throws AttributeNotFoundException, MBeanException, ReflectionException, InstanceNotFoundException, IOException {
    return remote.getAttribute(bean,attribute);
}


}




public class MemoryExtractor extends Thread{

final static Logger logger = Logger.getLogger(MemoryExtractor.class);
private static MBeanInfo memoryInfo;
private static ObjectName bean = null;
private static double MEMORY = 0.05;
private static long TIMEOUT = 3000;

public static void getMemoryInfo() {
    try {
        bean = new ObjectName("java.lang:type=Memory");
        checkWarningUsage();

    } catch (MalformedObjectNameException e) {
        logger.error("MemoryExtractor.java:25 " + e.getMessage());
    }
}

public static boolean checkWarningUsage() {
        try {
            logger.info("MemoryExtractor.java:46 Acessing memory details");
            CompositeData memoryUsage = (CompositeData) RemoteConnector.getMbeanAttribute(bean,"HeapMemoryUsage");


        } catch (Exception e) {
            logger.error("MemoryExtractor.java:58 " + e.getMessage());
        }
    return false;
}

public void run(){
    while (true){
        getMemoryInfo();
    }   
}
}

Неважно, синхронизируюсь я или нет, проблема все равно будет.

Трассировки стека

java.io.IOException: The client has been closed.
at com.sun.jmx.remote.internal.ClientCommunicatorAdmin.restart(ClientCommunicatorAdmin.java:94)
at com.sun.jmx.remote.internal.ClientCommunicatorAdmin.gotIOException(ClientCommunicatorAdmin.java:54)
at javax.management.remote.rmi.RMIConnector$RMIClientCommunicatorAdmin.gotIOException(RMIConnector.java:1474)
at javax.management.remote.rmi.RMIConnector$RemoteMBeanServerConnection.getAttribute(RMIConnector.java:910)
at org.wso2.connector.RemoteConnector.getMbeanAttribute(RemoteConnector.java:55)
at org.wso2.jvmDetails.MemoryExtractor.checkWarningUsage(MemoryExtractor.java:47)
at org.wso2.jvmDetails.MemoryExtractor.run(MemoryExtractor.java:79)

1 ответ

Решение

Вы кешируете ссылку на JMXConnector как static в вашем RemoteConnector класс, так что есть только одна связь. Как только первый поток закрывает одноэлементное соединение, в следующий раз любой другой поток попытается вызвать что-то, но это не удастся, потому что вы уже закрыли соединение в этот момент.

Если вы хотите иметь несколько потоков, то либо вы должны закрыть соединение после завершения всех потоков, либо иметь одно соединение на поток.

Другие вопросы по тегам