Java 完成完整的工作单元,直到发出停止信号
Java do complete units of work until signaled to stop
我有一些 (Linux) C 代码,我正在将其转换为 Java。该代码有一个主循环,用于在每个循环顶部检查来自 OS 的 TERM 信号,否则会阻止信号。这样,它在循环中所做的每个 "unit of work" 都已完全完成(不会被中间的 TERM 信号打断)。
这已证明 "interesting" 可以在 Java 中实施。我想出了一些测试代码(如下),它似乎可以工作,但我不确定它是否会一直工作,或者我是否刚刚 "lucky" 在我的测试中。
那么,这就是我的问题:这段代码是好代码还是有时碰巧可以工作的代码?
TL;DR: 工作线程和关闭线程调用一个通用的同步方法
public class TestShutdownHook {
static int a = 0; /* should end up 0 */
static volatile int b = 0; /* exit together */
static boolean go = true; /* signaled to stop */
/*
* this simulates a process that we want to do completely
* or not at all.
*/
private static void doitall () {
System.out.println("start");
++a; /* simulates half the unit of work */
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
System.out.println("exception"); /* doesn't seem to happen */
}
System.out.println("end");
--a; /* the other half */
}
/*
* there can be only one
*/
private static synchronized void syncit (String msg) {
if (msg.equals("exit")) go = false;
if (go) doitall();
}
/*
* starts a thread to wait for a shutdown signal,
* then goes into the 'while go doit' loop
*/
public static void main(String[] args) throws InterruptedException {
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
int n = 0;
System.out.println("Shutdown coming...");
syncit("exit"); /* can't happen while main is in syncit? */
System.out.println("Shutdown hook! " + a);
/* this isn't really needed, just lets us see "goodbye" */
while (b == 0) ++n;
System.out.println("adios..."+n);
}
});
while (go) {
syncit("loop");
// there needs to be something else in this loop
// otherwise, we will starve the shutdown thread.
// either of the two lines below seem sufficient
System.out.println("ok");
Thread.sleep(1);
}
System.out.println("goodbye");
b = 1;
}
}
只要关闭挂钩在您期望的所有情况下都是 运行(并已完成),就一定没问题。根据 Jarrod Roberson here,它似乎与 SIGTERM 一起按预期工作。如果您不需要使用信号处理程序显式捕获 OS 信号,我认为您不必担心。
所有可用的证据表明,如果您已经注册了 ShutdownHook,那么它会在 TERM 或 INT 信号传送到 JVM 时启动 并且所有其他线程将保持独立 直到 ShutdownHook 的 运行() 方法退出(当任何仍然 运行ning 将被终止时)。
因此,这导致了一个更简单的解决方案,它避免了 synchronized:
public class AnotherTestShutdownHook {
static int a = 0; /* should end up 0 */
static boolean go = true; /* signaled to stop */
static Thread mainThread = Thread.currentThread();
private static void trySleep ( int msecs ) {
try { Thread.sleep(msecs); } catch (InterruptedException e) {}
}
private static void tryJoin ( Thread t ) {
try { t.join(); } catch (InterruptedException e) {}
}
/*
* this simulates a process that we want to do completely
* or not at all.
*/
private static void doitall () {
System.out.println("start");
++a;
trySleep(5000);
System.out.println("end");
--a;
}
/*
* starts a thread to wait for a shutdown signal,
* then does units of work until told to stop
*/
public static void main(String[] args) {
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
System.out.println("Shutdown coming...");
go = false;
tryJoin(mainThread); // wait for mainThread to exit
System.out.println("Shutdown hook! " + a);
}
});
while (go) {
doitall();
}
System.out.println("goodbye");
}
}
我有一些 (Linux) C 代码,我正在将其转换为 Java。该代码有一个主循环,用于在每个循环顶部检查来自 OS 的 TERM 信号,否则会阻止信号。这样,它在循环中所做的每个 "unit of work" 都已完全完成(不会被中间的 TERM 信号打断)。
这已证明 "interesting" 可以在 Java 中实施。我想出了一些测试代码(如下),它似乎可以工作,但我不确定它是否会一直工作,或者我是否刚刚 "lucky" 在我的测试中。
那么,这就是我的问题:这段代码是好代码还是有时碰巧可以工作的代码?
TL;DR: 工作线程和关闭线程调用一个通用的同步方法
public class TestShutdownHook {
static int a = 0; /* should end up 0 */
static volatile int b = 0; /* exit together */
static boolean go = true; /* signaled to stop */
/*
* this simulates a process that we want to do completely
* or not at all.
*/
private static void doitall () {
System.out.println("start");
++a; /* simulates half the unit of work */
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
System.out.println("exception"); /* doesn't seem to happen */
}
System.out.println("end");
--a; /* the other half */
}
/*
* there can be only one
*/
private static synchronized void syncit (String msg) {
if (msg.equals("exit")) go = false;
if (go) doitall();
}
/*
* starts a thread to wait for a shutdown signal,
* then goes into the 'while go doit' loop
*/
public static void main(String[] args) throws InterruptedException {
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
int n = 0;
System.out.println("Shutdown coming...");
syncit("exit"); /* can't happen while main is in syncit? */
System.out.println("Shutdown hook! " + a);
/* this isn't really needed, just lets us see "goodbye" */
while (b == 0) ++n;
System.out.println("adios..."+n);
}
});
while (go) {
syncit("loop");
// there needs to be something else in this loop
// otherwise, we will starve the shutdown thread.
// either of the two lines below seem sufficient
System.out.println("ok");
Thread.sleep(1);
}
System.out.println("goodbye");
b = 1;
}
}
只要关闭挂钩在您期望的所有情况下都是 运行(并已完成),就一定没问题。根据 Jarrod Roberson here,它似乎与 SIGTERM 一起按预期工作。如果您不需要使用信号处理程序显式捕获 OS 信号,我认为您不必担心。
所有可用的证据表明,如果您已经注册了 ShutdownHook,那么它会在 TERM 或 INT 信号传送到 JVM 时启动 并且所有其他线程将保持独立 直到 ShutdownHook 的 运行() 方法退出(当任何仍然 运行ning 将被终止时)。
因此,这导致了一个更简单的解决方案,它避免了 synchronized:
public class AnotherTestShutdownHook {
static int a = 0; /* should end up 0 */
static boolean go = true; /* signaled to stop */
static Thread mainThread = Thread.currentThread();
private static void trySleep ( int msecs ) {
try { Thread.sleep(msecs); } catch (InterruptedException e) {}
}
private static void tryJoin ( Thread t ) {
try { t.join(); } catch (InterruptedException e) {}
}
/*
* this simulates a process that we want to do completely
* or not at all.
*/
private static void doitall () {
System.out.println("start");
++a;
trySleep(5000);
System.out.println("end");
--a;
}
/*
* starts a thread to wait for a shutdown signal,
* then does units of work until told to stop
*/
public static void main(String[] args) {
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
System.out.println("Shutdown coming...");
go = false;
tryJoin(mainThread); // wait for mainThread to exit
System.out.println("Shutdown hook! " + a);
}
});
while (go) {
doitall();
}
System.out.println("goodbye");
}
}