views:

229

answers:

2

I'm trying to make sure my Java application takes reasonable steps to be robust, and part of that involves shutting down gracefully. I am reading about shutdown hooks and I don't actually get how to make use of them in practice.

Is there a practical example out there?

Let's say I had a really simple application like this one below, which writes numbers to a file, 10 to a line, in batches of 100, and I want to make sure a given batch finishes if the program is interrupted. I get how to register a shutdown hook but I have no idea how to integrate that into my application. Any suggestions?

package com.example.test.concurrency;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintWriter;

public class GracefulShutdownTest1 {
    final private int N;
    final private File f;
    public GracefulShutdownTest1(File f, int N) { this.f=f; this.N = N; }

    public void run()
    {
        PrintWriter pw = null;
        try {
            FileOutputStream fos = new FileOutputStream(this.f);
            pw = new PrintWriter(fos);
            for (int i = 0; i < N; ++i)
                writeBatch(pw, i);
        }
        catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        finally
        {
            pw.close();
        }       
    }

    private void writeBatch(PrintWriter pw, int i) {
        for (int j = 0; j < 100; ++j)
        {
            int k = i*100+j;
            pw.write(Integer.toString(k));
            if ((j+1)%10 == 0)
                pw.write('\n');
            else
                pw.write(' ');
        }
    }

    static public void main(String[] args)
    {
        if (args.length < 2)
        {
            System.out.println("args = [file] [N] "
                    +"where file = output filename, N=batch count");
        }
        else
        {
            new GracefulShutdownTest1(
                    new File(args[0]), 
                    Integer.parseInt(args[1])
            ).run();
        }
    }
}
A: 

Search the forum/web for examples that use addShutdownHook method.

camickr
that's really not helpful. I googled several terms including addShutdownHook before writing this question.
Jason S
"This answer is not useful" - qualified (-1)
Andreas_D
Really? I've found examples in the past by doing searches.
camickr
@camickr: I just checked the top 10 results for googling "addShutdownHook example". None of them give useful example of coordinating the shutdown hook thread with the rest of the application. 1 result is the javadoc, 6 of them just print a message like "shutting down", 1 of them just barges in and close a file w/o coordinating with other threads, 1 does nothing but has a comment where something could be done, and the last one just shows automatic links to source code from two projects in Apache, without any context. Not useful, which is why I asked this question in the first place.
Jason S
-1 An answer of "just google/search for it" is actively discouraged. See e.g. http://meta.stackoverflow.com/questions/8724/how-to-deal-with-google-questions .
sleske
@sleske, I understand "just search" is discouraged. But accepting answers is also encouraged. The OP response that he doesn't have time is a joke. The posting in question posted working code. It would have taken 5 minutes maximum to verify the suggestions. I find it amazing that everybody here is worried about offending the person asking the question because they might not get any valued reputation points. I feel if the OP has time to continually post new questions on the forum they have time to accept/comment on old postings as well. A simple thank you goes a long way.
camickr
@camickr -- you're referring to a different question and if you want to discuss this I would suggest commenting on it there... but I would suggest we just drop this. You do not know my schedule or situation and I think you are making assumptions that are just off base.
Jason S
@Jason S, Dropped, since I see you finally found time out of your busy schedule to accept an answer.
camickr
+4  A: 

You could do the following:

  • Let the shutdown hook set some AtomicBoolean (or volatile boolean) "keepRunning" to false
  • (Optionally, .interrupt the working threads if they wait for data in some blocking call)
  • Wait for the working threads (executing writeBatch in your case) to finish, by calling the Thread.join() method on the working threads.
  • Terminate the program

Some sketchy code:

  • Add a static volatile boolean keepRunning = true;
  • In run() you change to

    for (int i = 0; i < N && keepRunning; ++i)
        writeBatch(pw, i);
    
  • In main() you add:

    final Thread mainThread = Thread.currentThread();
    Runtime.getRuntime().addShutdownHook(new Thread() {
        public void run() {
            keepRunning = false;
            mainThread.join();
        }
    });
    

That's roughly how I do a graceful "reject all clients upon hitting Control-C" in terminal.


From the docs:

When the virtual machine begins its shutdown sequence it will start all registered shutdown hooks in some unspecified order and let them run concurrently. When all the hooks have finished it will then run all uninvoked finalizers if finalization-on-exit has been enabled. Finally, the virtual machine will halt.

That is, a shutdown hook keeps the JVM running until the hook has terminated (returned from the run()-method.

aioobe
Ah -- so if I understand right, the gist of what you're saying is that the shutdown hook has an opportunity to communicate with other currently-running threads, and to hold off the VM shutdown (e.g. by using Thread.join()) until it is satisfied that a quick cleanup has been completed. That's the point I was missing. thanks!
Jason S
Yes. You got it. Updated the answer with a few sentences from the docs.
aioobe