0717-7821348
关于我们

欢乐彩代理

您现在的位置: 首页 > 关于我们 > 欢乐彩代理
欢乐彩票app是正规的吗-怎么高雅地中止Java进程
2019-05-29 22:19:49

了解间断Java进程的实质

咱们知道,Java程序的运转需求一个运转时环境,即:JVM,发动Java进程即发动了一个JVM。

因而,所谓间断Java进程,实质上便是封闭JVM。

那么,哪些状况会导致JVM封闭呢?

应该怎么正确地间断Java进程

一般来讲,间断一个进程只需求杀死进程即可。

可是,在某些状况下或许需求在JVM封闭之前履行一些数据保存或许资源开释的作业,此刻就不能直接强制杀死Java进程。

  1. 关于正常封闭或反常封闭的几种状况,JVM封闭前,都会调用已注册的封闭钩子,依据这种机制,咱们能够将扫尾的作业放在封闭钩子中,进而使咱们的运用程序安全的退出。并且,依据渠道通用性的考虑,更引荐运用程序运用System.exit(0)这种办法退出JVM。
  2. 关于强制封闭的几种状况:体系关机,操作体系会告诉JVM进程等候封闭,一旦等候超时,体系会强制间断JVM进程;而kill -9、Runtime.halt()、断电、体系crash这些办法会直接无商议间断JVM进程,JVM彻底没有履行扫尾作业的机遇。

综上所述:

  1. 除非十分确认不需求在Java进程退出之前履行收尾的作业,不然激烈不主张运用kill -9这种简略暴力的办法强制间断Java进程(除了体系关机,体系Crash,断电,和Runtime.halt()咱们力不从心之外)。
  2. 不管怎么,都应该在Java进程中注册封闭钩子,尽最大或许地确保在Java进程退出之前做一些善后的作业(实践上,大多数时分都需求这样做)。

怎么注册封闭钩子

在Java中注册封闭钩子经过Runtime类完成:

Runtime.getRuntime().addShutdownHook(new Thread(){
@Override
public void run() {
// 在JVM封闭之前履行收尾作业
// 注意事项:
// 1.在这里履行的动作不能耗时太久
// 2.不能在这里再履行注册,移除封闭钩子的操作
// 3 不能在这里调用System.exit()
System.out.println("do shutdown hook");
}
});

为JVM注册封闭钩子的机遇不固定,能够在发动Java进程之前,也能够在Java进程之后(如:在监听到操作体系信号量之后再注册封闭钩子也是能够的)。

运用封闭钩子的注意事项

1.封闭钩子实质上是一个线程(也称为Hook线程),关于一个JVM中注册的多个封闭钩子它们将会并发履行,所以JVM并不确保它们的履行次序;由所以并发履行的,那么很或许由于代码不妥导致呈现竞态条件或死锁等问题,为了防止该问题,激烈主张只注册一个钩子并在其间履行一系列操作。

2.Hook线程会推迟JVM的封闭时刻,这就要求在编写钩子进程中有必要要尽或许的削减Hook线程的履行时刻,防止hook线程中呈现耗时的核算、等候用户I/O等等操作。

3.封闭钩子履行进程中或许被强制打断,比如在操作体系关机时,操作体系会等候进程间断,等候超时,进程仍未间断,操作体系会强制的杀死该进程,在这类状况下,封闭钩子在履行进程中被强制间断。

4.在封闭钩子中,不能履行注册、移除钩子的操作,JVM将封闭钩子序列初始化完毕后,不允许再次增加或许移除现已存在的钩子,不然JVM抛出IllegalStateException反常。

5.不能在钩子调用System.exit(),不然卡住JVM的封闭进程,可是能够调用Runtime.halt()。

6.Hook线程中同样会抛出反常,关于未捕捉的反常,线程的默许反常处理器处理该反常(将反常信息打印到System.err),不会影响其他hook线程以及JVM正常退出。

信号量机制

注册封闭钩子的意图是为了在JVM封闭之前履行一些收尾的动作,而从上述描绘能够知道,触发封闭钩子动作的履行需求满意JVM正常封闭或反常封闭的景象。

明显,咱们应该正常封闭JVM(反常封闭JVM的景象不期望发作,也无法百分之百地彻底根绝),即履行:System.exit(),Ctrl + C, kill -15 进程ID。

  • System.exit():一般咱们在程序运转完毕之后调用,这是在运用代码中写死的,无法在进程外部进行调用。
  • Ctrl + C:假如Java进程运转在操作体系前台,能够经过键盘中止的办法完毕运转;可是当进程在后台运转时,就无法经过Ctrl + C办法退出了。
  • Kill (-15)SIGTERM信号:运用kill指令完毕进程是运用操作体系的信号量机制,不管进程运转在操作体系前台仍是后台,都能够经过kill指令完毕进程,这也是完毕进程运用得最多的办法。

实践上,大多数状况下的进程完毕操作一般是在进程运转进程中需求间断进程或许重启进程,而不是等候进程自己运转完毕(服务程序都是一向运转的,并不会自动完毕)。也便是说,针对JVM正常封闭的景象,大多数状况是运用kill -15 进程ID的办法完成的。那么,咱们是否能够结合操作体系的信号量机制和JVM的封闭钩欢乐彩票app是正规的吗-怎么高雅地中止Java进程子完成高雅地封闭Java进程呢?答欢乐彩票app是正规的吗-怎么高雅地中止Java进程案是必定的,详细完成过程如下:

第一步:在运用程序中监听信号量

由于不通的操作体系类型完成的信号量动作存在差异,所以监听的信号量需求依据Java进程实践运转的环境而定(如:Windows运用SIGINT,Linux运用SIGTERM)。

Signal sg = new Signal("TERM"); // kill -15 pid
Signal.handle(sg, new SignalHandler() {
@Override
public void handle(Signal signal) {
System.out.println("signal handle: " + signal.getName());
// 监听信号量,经过System.exit(0)正常封闭JVM,触发封闭钩子履行收尾作业
System.exit(0);
}
});

第二步:注册封闭钩子

Runtime.getRuntime().addShutdownHook(new Thread(){
@Override
public void run() {
// 履行进程退出前的作业
// 注意事项:
// 1.在这里履行的动作不能耗时太久
// 2.不能在这里再履行注册,移除封闭钩子的操作
// 3 不能在这里调用System.exit()
System.out.println("do something");
}
});

完好示例如人民币对美金下:

public class ShutdownTest {
public static void main(String[] args) {
System.out.println("Shutdown Test");
Signal sg = new Signal("TERM"); // kill -15 pid
// 监听信号量
Signal.handle(sg, new Signa欢乐彩票app是正规的吗-怎么高雅地中止Java进程lHandler() {
@Override
public void handle(Signal signal) {
System.out.println("signal handle: " + signal.getName());
System.exit(0);
}
});
// 注册封闭钩子
Runtime.getRuntime().addShutdownHook(new Thread(){
@Override
public void run() {
// 在封闭钩子中履行收尾作业
// 注意事项:
// 1.在这里履行的动作不能耗时太久
// 2.不能在这里再履行注册,移除封闭钩子的操作
// 3 不能在这里调用System.exit()
System.out.println("do shutdown hook");
}
});
mockWork();
System.out.println("Done.");
System.exit(0);
}
// 模仿进程正在运转
private static void mockWork() {
//mockRuntimeException();
//mo欢乐彩票app是正规的吗-怎么高雅地中止Java进程ckOOM();
try {
Thread.sleep(120 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 模仿在运用中抛出RuntimeException时会调用注册钩子
private static void mockRuntimeException() {
throw new RuntimeException("This is a mock runtime ex");
}
// 模仿运用运转呈现OOM时会调用注册钩子
// -xms10m -xmx10m
private static void mockOOM() {
List list = new ArrayList();
for(int i = 0; i < 1000000; i++) {
list.add(new Object());
}
}
}

总结

网上有文章总结说能够直接运用监听信号量的机制来完成高雅地封闭Java进程(详见:Java程序高雅封闭的两种办法),实践上这是有问题的。由于单纯地监听信号量,并不能掩盖到反常封闭JVM的景象(如:RuntimeException或OOM),这种办法与注册封闭钩子的差异在于:

1.封闭钩子是在独立线程中运转的,当运用进程被kill的时分main函数就现已完毕了,仅会运转ShutdownHook线程中run()办法的代码。

2.监听信号量办法中handle函数会在进程被kill时收到TERM信号,但对main函数的运转不会有任何影响,需求运用其他办法完毕main函数(如:在main函数中增加布尔类型的flag,当收到TERM信号时修正该flag,程序便会正常完毕;或许在handle函数中调用System.exit())。