【问题标题】:Java do complete units of work until signaled to stopJava 完成工作单元,直到发出停止信号
【发布时间】:2016-05-30 15:01:24
【问题描述】:

我有一些 (Linux) C 代码正在转换为 Java。该代码有一个主循环,用于在每个循环顶部检查来自操作系统的 TERM 信号,否则会阻止信号。这样一来,它在循环中所做的每个“工作单元”都已完全完成(不会被中间的 TERM 信号中断)。

事实证明,这在 Java 中实现有点“有趣”。我想出了一些测试代码(如下),它似乎可以工作,但我不确定它是否会一直有效,或者我是否只是在测试中“幸运”。

所以,这是我的问题:这是好的代码还是只是偶尔会工作的代码?

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;
    }
}

【问题讨论】:

  • 为什么认为它不会每次都起作用?我没有看到任何缺陷,在退出信号上,如果 JVM 正常关闭或使用 ^C 关闭,doitall() 应该完成工作。我猜你已经阅读了 Java 文档。
  • 我在谷歌上搜索了很多关于 JNI 和 sun.misc.motled.corpse 的话题,“你不是在思考 Java 方式”等等,但是我没有找到这种方法,所以我有些自我怀疑。

标签: java signals synchronized atomic shutdown-hook


【解决方案1】:

只要在您期望的所有情况下运行(并完成)关闭挂钩,它就一定没问题。根据Jarrod Roberson here,它似乎与 SIGTERM 一样正常工作。如果您不需要使用信号处理程序显式捕获操作系统信号,我认为您无需担心。

【讨论】:

  • 感谢您促使我重新阅读该问题——我认为这是最有用的 idelvall's 答案——他想关闭所有其他线程,但这只是一个短暂的飞跃在那里要求他们很好地结束。
【解决方案2】:

所有可用的证据都表明,如果你已经注册了一个ShutdownHook,那么它将在一个TERM或INT信号被传递到JVM时启动并且所有其他线程都将被单独处理 直到 ShutdownHook 的 run() 方法退出(此时任何仍在运行的将被终止)。

因此,这导致了一个避免同步的更简单的解决方案:

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");
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-04-14
    • 2015-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-03
    相关资源
    最近更新 更多