2012-09-28 107 views
2

我試圖啓動一個JMXConnectorServer用於管理和調試目的。但是我不希望這個服務阻止應用程序在最後一個非守護線程終止時正常退出。如何自動關閉JMXConnectorServer

換句話說,我想下面的程序立即終止:

public class Main { 
    public static void main(final String[] args) throws IOException { 
     MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); 
     JMXServiceURL jmxUrl = new JMXServiceURL("rmi", null, 0); 
     JMXConnectorServer connectorServer = 
      JMXConnectorServerFactory.newJMXConnectorServer(jmxUrl, null, mbs); 
     connectorServer.start(); 
    } 
} 

回答

0
String port = getProperty("com.sun.management.jmxremote.port"); 
if (port == null) { 
    port = String.valueOf(getAvailablePort()); 
    System.setProperty("com.sun.management.jmxremote.port", port); 
    System.setProperty("com.sun.management.jmxremote.ssl", "false"); 
    System.setProperty("com.sun.management.jmxremote.authenticate", "false"); 

    sun.management.Agent.startAgent(); 
} 
log.info(InetAddress.getLocalHost().getCanonicalHostName() + ":" + port); 
+0

這是兩個答案中的一個,對嗎?哪一個解決了你的問題?你可以通過發佈兩個答案並接受你更喜歡的答案來清楚地說明問題。 – oberlies

0

你可以添加一個JVM Shutdown Hook停止連接器服務器。

===== UPDATE =====

不知道爲什麼你關閉掛鉤不起作用。也許你可以提供你的示例代碼。這裏有一個例子:

public static void main(String[] args) {   
    try { 
     log("Creating Connector Server"); 
     final JMXConnectorServer jcs = JMXConnectorServerFactory.newJMXConnectorServer(new JMXServiceURL("rmi", "localhost", 12387), null, ManagementFactory.getPlatformMBeanServer()); 
     Thread jcsStopper = new Thread("JCS-Stopper") { 
      public void run() { 
       if(jcs.isActive()) { 
        try { 
         jcs.stop(); 
         log("Connector Server Stopped"); 
        } catch (Exception e) { 
         log("Failed to stop JCS"); 
         e.printStackTrace(); 
        }      
       } 
      } 
     }; 
     jcsStopper.setDaemon(false); 
     Runtime.getRuntime().addShutdownHook(jcsStopper); 
     log("Registered Server Stop Task"); 
     jcs.start(); 
     log("Server Started"); 
     Thread.sleep(3000); 
     System.exit(0); 

    } catch (Exception ex) { 
     ex.printStackTrace(System.err); 
    } 
} 

輸出是:

[main]:Creating Connector Server 
[main]:Registered Server Stop Task 
[main]:Server Started 
[JCS-Stopper]:Connector Server Stopped 
+0

不爲我工作。在這種情況下,更新的Shutdown Hook需要我。你能否提供一個適合你的例子? –

1

呀,你將需要這麼connectorServer.stop();在一些點。

編輯:

在閱讀您的意見,這聽起來像你應該這樣做:

connectorServer.start(); 
try { 
    // create thread-pool 
    ExecutorService threadPool = Executors... 
    // submit jobs to the thread-pool 
    ... 
    threadPool.shutdown(); 
    // wait for the submitted jobs to finish 
    threadPool.awaitTermination(Long.MAX_LONG, TimeUnit.SECONDS); 
} finally { 
    connectorServer.stop(); 
} 

@Nicholas'的關閉掛鉤的想法是好的。但是,通常情況下,我的main線程正在等待來自shutdown() JMX操作的某種變量。喜歡的東西:

public CountDownLatch shutdownLatch = new CountDownLatch(1); 
... 

// in main 
connectorServer.start(); 
try { 
    // do the main-thread stuff 
    shutdownLatch.await(); 
} finally { 
    connectorServer.stop(); 
} 

// in some JMX exposed operation 
public void shutdown() { 
    Main.shutdownLatch.countDown(); 
} 

順便說一句,你可以用我的SimpleJMX包來管理您的服務器JMX你。

JmxServer jmxServer = new JmxServer(8000); 
jmxServer.start(); 
try { 
    // register our lookupCache object defined below 
    jmxServer.register(lookupCache); 
    jmxServer.register(someOtherObject); 
} finally { 
    jmxServer.stop(); 
} 
+0

我的申請很複雜。它啓動線程池進行多線程處理。我無法處理閂鎖。我想要的只是RMI接受Tread守護進程。 –

+0

應用程序知道如何關閉@MykhayloAdamovych?它會收到一條消息嗎?無論如何關閉應用程序應調用'shutdown()'方法。 – Gray

+0

當最後一個非後臺進程線程退出時,應用程序正常關閉。 –

1

我有類似的問題,玩,寫了這個類:

public final class HardDaemonizer extends Thread { 

    private final Runnable target; 
    private final String newThreadName; 

    public HardDaemonizer(Runnable target, String name, String newThreadName) { 
     super(name == null ? "Daemonizer" : name); 
     setDaemon(true); 
     this.target = target; 
     this.newThreadName = newThreadName; 
    } 

    @Override 
    public void run() { 
     try { 
      List<Thread> tb = getSubThreads(); 
      target.run(); 
      List<Thread> ta = new java.util.ArrayList<>(getSubThreads()); 
      ta.removeAll(tb); 
      for (Thread thread : ta) { 
       thread.setName(newThreadName); 
      } 
      Thread.sleep(Long.MAX_VALUE); 
     } catch (InterruptedException ex) { 
      Logger.getLogger(HardDaemonizer.class.getName()).log(Level.SEVERE, null, ex); 
     } 
    } 

    public static Thread daemonize(String daemonizerName, String newThreadName, Runnable target) { 
     HardDaemonizer daemonizer = new HardDaemonizer(target, daemonizerName, newThreadName); 
     daemonizer.start(); 
     return daemonizer; 
    } 

    private static List<Thread> getSubThreads() { 
     ThreadGroup group = Thread.currentThread().getThreadGroup().getParent(); 
     Thread[] threads = new Thread[group.activeCount()]; 
     group.enumerate(threads); 
     return java.util.Arrays.asList(threads); 
    } 
} 

你可以這樣使用它:

HardDaemonizer.daemonize(null, "ConnectorServer", new Runnable(){ 
    @Override 
    public void run() { 
     try { 
      connectorServer.start(); 
     } catch (IOException ex) { 
      Logger.getLogger(Ralph.class.getName()).log(Level.SEVERE, null, ex); 
     } 
    } 
}); 

要小心 - 它的棘手!


編輯

哎......這不是爲您解決。它僅硬連接器線程,並且該線程在jvm停止時將被終止。另外,您可以自定義此線程的名稱。

或者,您可以添加標誌completed並在daemonize中循環睡眠,直到連接器服務器啓動。


簡化

這不靠譜的線程重命名簡化daemonizer:

public abstract class Daemonizer<T> extends Thread { 

    private final T target; 
    private boolean completed = false; 
    private Exception cause = null; 

    public Daemonizer(T target) { 
     super(Daemonizer.class.getSimpleName()); 
     setDaemon(true); 
     this.target = target; 
    } 

    @Override 
    public void run() { 
     try { 
      act(target); 
     } catch (Exception ex) { 
      cause = ex; 
     } 
     completed = true; 
     try { 
      Thread.sleep(Long.MAX_VALUE); 
     } catch (InterruptedException ex) { 
     java.util.logging.Logger.getLogger(Daemonizer.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); 
     } 
    } 

    public abstract void act(final T target) throws Exception; 

    public static void daemonize(Daemonizer daemonizer) throws Exception { 
     daemonizer.start(); 
     while (!daemonizer.completed) { 
      Thread.sleep(50); 
     } 
     if (daemonizer.cause != null) { 
      throw daemonizer.cause; 
     } 
    } 
} 

用法:

Daemonizer.daemonize(new Daemonizer<JMXConnectorServer>(server) { 
    @Override 
    public void act(JMXConnectorServer server) throws Exception { 
     server.start(); 
    } 
}); 
0

從我的經驗來看,JMXConnectorServer僅在運行用戶線程,當你明確地創建它。

如果您改爲通過系統屬性爲平臺MBean服務器配置RMI訪問,則隱式創建的JMX連接器服務器將作爲守護進程運行並且不會阻止JMV關閉。要做到這一點,你的代碼將縮小到以下

public class Main { 
    public static void main(final String[] args) throws IOException { 
     MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); 
    } 
} 

但你需要設置以下系統屬性:

-Dcom.sun.management.jmxremote.port=1919 
-Dcom.sun.management.jmxremote.authenticate=false 
-Dcom.sun.management.jmxremote.ssl=false