-1

java.lang.Thread.setDaemon(boolean)

The Java Virtual Machine exits when the only threads running are all daemon threads.

YET IN THE BELOW CODE "SAFELY SHUTTING DOWN" never happens while interrupting(OS style) the process and no i'm not using SIGKILL...

since the documentation is wrong (?) is my only recourse to keep track of all non-daemon threads and join on them in the shutdown hook?

public class Main {
  public static void main(String... args) {
    Runtime.getRuntime().addShutdownHook(new Thread() {
      public void run() {
        System.out.println("shutdown hook activated");
      }
    });
    new Thread(new Runnable() {
      public void run() {
        while (true) {
          try {
            System.out.println("sleeping for 1000 seconds!");
            Thread.sleep(1000000);
          } catch (InterruptedException e) {
            System.out.println("INTERRUPTED");
            break;
          }
        }
        System.out.println("SAFELY SHUTTING DOWN");
      }
    }).start();
  }
}
jtahlborn
  • 52,909
  • 5
  • 76
  • 118
user3338098
  • 907
  • 1
  • 17
  • 38
  • 4
    The documentation is not wrong. Logically, "the Java Virtual Machine exits when the only threads running are all daemon threads" does *not* imply that it doesn't also shut down in other circumstances. – Kevin Krumwiede Aug 27 '14 at 19:20
  • Show us what you mean by _interrupt process_. – Sotirios Delimanolis Aug 27 '14 at 19:23
  • Non daemon threads stop your java program from exiting _on its own_. they do not stop the java program from being killed externally. (otherwise you could make a non-terminating program) – jtahlborn Aug 27 '14 at 19:23
  • interrupt="kill -s SIGINT JAVA_PID" – user3338098 Aug 27 '14 at 19:26
  • "otherwise you could make a non-terminating program", but I should be able to, C programs do that all the time! – user3338098 Aug 27 '14 at 19:27
  • "all the time"? i would be very upset if i had lots of programs on my computer that refused to exit when i told them to... – jtahlborn Aug 27 '14 at 19:30
  • @KevinKrumwiede please note this is not an "abnormal" termination, it's a simple SIGINT, and the shutdown hook does get called as expected, but after the shutdown hook is done the JVM CHOOSES to kill all my non-daemon threads (in contradiction to the quoted documentation) – user3338098 Aug 27 '14 at 19:30
  • you can install signal handlers in the sun jvm if you really want to. – jtahlborn Aug 27 '14 at 19:31
  • @jtahlborn I often use "kill PID" and get no results on a misbehaving program and have to resort to using "kill -s SIGKILL PID" – user3338098 Aug 27 '14 at 19:31
  • 1
    it's already been explained what the documentation means, so your example does not contradict the documentation. – jtahlborn Aug 27 '14 at 19:32
  • yes, sometimes i get the same behavior when java programs misbehave. but that's not "normal" programming for the application. – jtahlborn Aug 27 '14 at 19:33
  • @jtahlborn "already been explained what the documentation means"...? http://publib.boulder.ibm.com/infocenter/realtime/v1r0/index.jsp?topic=%2Fcom.ibm.rt.doc.10%2Fuser%2Fsighand.html considers a SIGINT to result in "normal" termination, thus "normal" documentation should apply... yet I get the opposite of what the documentation says... – user3338098 Aug 27 '14 at 19:46
  • @jtahlborn "thats not "normal" programming"... I have also come accross programs that when interrupting will ask "Are you sure you want to quit?"... :-) – user3338098 Aug 27 '14 at 19:47
  • 1
    "Once the shutdown sequence has begun it can be stopped only by invoking the halt method, which forcibly terminates the virtual machine." The shutdown hook documentation is pretty clear about the fact that you can't use it to stop the shutdown (well if you read the rest of the docu you'll see the loophole, but ugh horribly brittle that) – Voo Aug 27 '14 at 19:51
  • 1
    The [Oracle documentation](http://docs.oracle.com/javase/7/docs/technotes/tools/solaris/java.html) mentions `SIGINT` and `abrupt termination` in the same breath. You're also aware that shutdown hooks may never be called right ? – Deepak Bala Aug 27 '14 at 19:53
  • 1
    @user3338098 You are not getting "the opposite of what the documentation says." As I said, the documentation you quoted does not say or imply anything at all about the problem you're trying to solve. You are interpreting it illogically. Specifically, you are denying the antecedent. http://en.wikipedia.org/wiki/Denying_the_antecedent – Kevin Krumwiede Aug 27 '14 at 20:13
  • i've never personally had a program prompt me when i sent it a signal. i'm not even sure you can legally do interactive stuff in a signal handler. – jtahlborn Aug 27 '14 at 20:21
  • maybe this is a better direction: what are you _actually_ trying to accomplish (the high level goal, not the "stopping shutdown thing")? – jtahlborn Aug 27 '14 at 20:22
  • @jtahlborn There are definitely ways to do so legally (and a ton more that lead to undefined behavior) and it's not unheard of. You can't do that with Java though (well I can think of two options actually, but gosh I don't want spread such ideas) – Voo Aug 27 '14 at 22:07

2 Answers2

1

Note the javadoc of Runtime#addShutdownHook(Thread).

The Java virtual machine shuts down in response to two kinds of events:

  • The program exits normally, when the last non-daemon thread exits or when the exit (equivalently, System.exit) method is invoked, or
  • The virtual machine is terminated in response to a user interrupt, such as typing ^C, or a system-wide event, such as user logoff or system shutdown.

A SIGINT is a user interrupt, equivalent to ^C on the command line.

This javadoc states how shutdown hooks behave for those conditions.

The javadoc you've quoted explains how the JVM behaves in the context of daemon threads.

They are not mutually exclusive. Additionally, nothing indicates that your running threads will be interrupted.

Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
0

I think the problem is that your shutdown hook is incomplete. The hook needs to wait until the "SAFELY SHUTTING DOWN" action is complete before it returns.

Here is a modified version of your code that does work.

public static void main(String... args)  {

    final AtomicBoolean shouldBeRunning = new AtomicBoolean(true);
    final AtomicBoolean isRunning = new AtomicBoolean(false);

    Runtime.getRuntime().addShutdownHook(new Thread() {
        public void run() {
            shouldBeRunning.set(false);
            System.out.println("shutdown hook activated");
            while(isRunning.get()) {
                try {
                    System.out.println("waiting on safe shutdown to complete");
                    Thread.sleep(250);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    });
    new Thread(new Runnable() {
        public void run() {
            isRunning.set(true);
            while (shouldBeRunning.get()) {
                try {
                    System.out.println("sleeping for 1 seconds!");
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    System.out.println("INTERRUPTED");
                    break;
                }
            }
            System.out.println("SAFELY SHUTTING DOWN");
            isRunning.set(false);
        }
    }).start();
}

public static void main(String... args) throws InterruptedException {

    final AtomicBoolean shouldBeRunning = new AtomicBoolean(true);
    final AtomicBoolean isRunning = new AtomicBoolean(false);

    Runtime.getRuntime().addShutdownHook(new Thread() {
        public void run() {
            shouldBeRunning.set(false);
            System.out.println("shutdown hook activated");
            while(isRunning.get()) {
                try {
                    System.out.println("waiting on safe shutdown to complete");
                    Thread.sleep(250);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    });
    new Thread(new Runnable() {
        public void run() {
            isRunning.set(true);
            while (shouldBeRunning.get()) {
                try {
                    System.out.println("sleeping for 1 second!");
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    System.out.println("INTERRUPTED");
                    break;
                }
            }
            System.out.println("SAFELY SHUTTING DOWN");
            isRunning.set(false);
        }
    }).start();
}

The output is:

sleeping for 1 second!
sleeping for 1 second!
shutdown hook activated
waiting on safe shutdown to complete
waiting on safe shutdown to complete
SAFELY SHUTTING DOWN

Tracking all the non daemon threads and joining on them in the shutdown hook won't allow you to prevent your program from being terminated since the shutdown hook has a time limit. When this time expires the JVM will exit even if the hook has not completed.