Java 如何自动关闭JMXConnectorServer
出于管理和调试目的,我正在尝试启动JMXConnectorServer。但我不希望这个服务阻止应用程序在最后一个非守护进程线程终止时正常退出 换句话说,我希望以下程序立即终止:Java 如何自动关闭JMXConnectorServer,java,jmx,Java,Jmx,出于管理和调试目的,我正在尝试启动JMXConnectorServer。但我不希望这个服务阻止应用程序在最后一个非守护进程线程终止时正常退出 换句话说,我希望以下程序立即终止: public class Main { public static void main(final String[] args) throws IOException { MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
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();
}
}
您可以添加用于停止连接器服务器的
====更新=====
不知道为什么你的关机挂钩不工作。也许您可以提供示例代码。下面是一个例子:
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
是的,您需要这样一个
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();
}
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();
}
@尼古拉斯关于关机挂钩的想法很好。然而,通常情况下,我让我的main
线程等待从shutdown()
JMX操作设置的某种变量。比如:
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();
}
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();
}
另外,您可以使用我的包为您管理JMX服务器
JmxServer jmxServer = new JmxServer(8000);
jmxServer.start();
try {
// register our lookupCache object defined below
jmxServer.register(lookupCache);
jmxServer.register(someOtherObject);
} finally {
jmxServer.stop();
}
我玩过类似的游戏,写过这样一节课:
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);
}
}
小心——这很棘手
编辑
啊。。。这不是你的解决方案。它很难仅对连接器线程进行守护,当jvm停止时,该线程将被终止。此外,您还可以自定义此线程的名称
或者,您可以添加标志completed
并在daemonize
方法中循环休眠,直到连接器服务器启动
简化的
这是简化的守护程序,无需复杂的线程重命名:
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;
}
}
}
公共抽象类守护进程扩展线程{
私人最终目标;
private boolean completed=false;
私有异常原因=null;
公共守护程序(T目标){
super(Daemonizer.class.getSimpleName());
setDaemon(true);
this.target=目标;
}
@凌驾
公开募捐{
试一试{
行动(目标);
}捕获(例外情况除外){
原因=ex;
}
完成=正确;
试一试{
线程睡眠(长.MAX_值);
}捕获(中断异常例外){
getLogger(Daemonizer.class.getName()).log(java.util.logging.Level.SEVERE,null,ex);
}
}
公共抽象无效法案(最终T目标)抛出异常;
公共静态无效daemonize(Daemonizer Daemonizer)引发异常{
daemonizer.start();
而(!daemonizer.completed){
睡眠(50);
}
if(daemonizer.cause!=null){
抛出daemonizer.cause;
}
}
}
用法:
Daemonizer.daemonize(new Daemonizer<JMXConnectorServer>(server) {
@Override
public void act(JMXConnectorServer server) throws Exception {
server.start();
}
});
Daemonizer.daemonize(新的Daemonizer(服务器){
@凌驾
public void act(JMXConnectorServer服务器)引发异常{
server.start();
}
});
根据我的经验,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
不适合我。在这种情况下,有人找我。你能提供一个对你有用的例子吗?我的应用程序很复杂。它在多线程中启动线程池进行处理。我对付不了拉奇。我只想让RMI成为守护进程。应用程序如何知道关闭@mykhayoladamovych?它收到消息了吗?任何应该关闭应用程序的操作都应该调用shutdown()
方法。当最后一个非守护进程线程退出时,应用程序“正常”关闭。确定。您希望应用程序何时关闭@mykhayoladamovych?显然,您不希望主应用程序退出并停止应用程序。最后一个运行的非守护进程线程是什么?它如何知道退出?我希望main(非守护进程)在一天左右的时间内启动线程池(多个非守护进程线程)处理数据。。。正常退出。我不想手动关机。最后一个非守护进程线程是线程池中最后一个处理线程的线程。在这里面我想监控里面发生了什么…这是一个两个答案,对吗?哪一个为你解决了这个问题?你可以通过张贴两个答案并接受一个你更喜欢的答案来说明这一点。