0

I have a Java application which has some infinitely running threads polling the back-end Database. When the JVM is shutdown (via weblogic UI) I need to perform some cleanup operations for each of the threads, like connecting to DB and setting status of running transactions from "in-progress" to "unprocessed".

Is there a way to write a method in each of the thread, which will be called when the thread is going to be stopped by JVM?

I know about shutdown hooks but I need the data from the variables in the thread to understand which status to change in Db and in the implementations of shutdown hooks it seems a separate hook thread is started which will not have the data from the original threads.

  • If you only need to handle gracefully shutting down you can use either interrupts or an atomic Boolean to identify shutdown. – Roy Shahaf Sep 18 '18 at 06:01

1 Answers1

1

Since you have access to those threads (I mean you can modify their code) then you can:

  1. Do not allow the user to stop the application from exiting in a normal way. You are going to stop it for him once you are prompted by him to do so. This is where you need the hook. For example if the application is based on a JFrame then add a windowClosing() hook to gracefully stop the running Threads and at the same time set the default close operation of the frame to DO_NOTHING_ON_CLOSE. Take a look at my code in this answer below...
  2. Put a stoping flag in the infinite loops, making them finite.
  3. When the shutdown is going to occur, alter those flags so that each Thread exits the loop.
  4. When out of the loop the Thread will make any changes necessary (with full access to all of its variables) and then exit the run() method.
  5. Meanwhile, in the main Thread (i.e. the Thread which marked all other Threads to stop), you are going to join() each finite Thread.
    This method allows to wait for a Thread to execute completely (i.e. exit its run() method).
  6. Finally, the main Thread, is going to call for example System.exit(0); to exit the whole application, because this is supposedly the last desired action by the user.

Note: this assumes that the user is going to close the application with normal actions. If for example the user is going to kill the application via the Windows' Task Manager for example, then this approach won't work. I don't know about shutdown hooks on Threads...

Follows example code (read the comments):

import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class GraceDown {
    private static class MyThread extends Thread {
        private boolean keepGoing = true; //This is the stopping flag.
        private final int i; //In this case i marks the 'id' of the Thread, but it is also an arbitary variable that the Thread has acccess in its final moments...

        public MyThread(final int i) {
            this.i = i;
        }

        private synchronized boolean isKeepGoing() {
            return keepGoing; //Tells if we should exit the loop and start the stopping operation...
        }

        public synchronized void startShutdown() {
            keepGoing = false; //Tells we should exit the loop and start the stopping operation.
        }

        @Override
        public void run() {

            while (isKeepGoing()) { //After every complete loop, we check the if we can go on.
                //Your 'infinite' loop actions go in here:
                try { Thread.sleep(1000); } catch (final InterruptedException ie) {}
                System.out.println("Thread " + i + " running...");
            }

            //Your gracefull shutdown actions go here...
            System.out.println("Thread " + i + ": my stopping actions go here! Look, I have access to all my variables (such as i)! ;)");
        }
    }

    public static void main(final String[] args) {
        //Create and start the Threads:
        final MyThread[] myThreads = new MyThread[5];
        for (int i = 0; i < myThreads.length; ++i)
            myThreads[i] = new MyThread(i);
        for (int i = 0; i < myThreads.length; ++i)
            myThreads[i].start();

        final JFrame frame = new JFrame("Lets close me...");
        frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); //IMPORTANT STEP! This means we are going to close the application instead of it being closed automatically when the user presses to close the window...

        //Adding the 'hook':
        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(final WindowEvent wevt) {
                System.out.println("Initializing shutdown...");
                //This is where the thread is going to stop all others...
                for (int i = 0; i < myThreads.length; ++i)
                    myThreads[i].startShutdown();

                //Wait for all threads to stop:
                for (int i = 0; i < myThreads.length; ++i)
                    try { myThreads[i].join(); } catch (final InterruptedException ie) { System.err.println("Error gracefully shutdowning the Thread!!!"); }

                //Now we can exit the JVM:
                System.out.println("Exiting JVM...");
                System.exit(0); //Code '0' indicates exiting without error(s).
            }
        });

        frame.getContentPane().add(new JLabel("Close this window and the Threads will shutdown gracefully...", JLabel.CENTER));
        frame.pack();
        frame.setLocationRelativeTo(null); //Put the packed frame on the center of the default screen.
        frame.setVisible(true);
    }
}

The above should print something like this:

Thread 1 running...
Thread 4 running...
Thread 0 running...
Thread 2 running...
Thread 3 running...
Thread 3 running...
Thread 4 running...
Thread 2 running...
Thread 1 running...
Thread 0 running...
Initializing shutdown...
Thread 2 running...
Thread 2: my stopping actions go here! Look, I have access to all my variables (such as i)! ;)
Thread 0 running...
Thread 0: my stopping actions go here! Look, I have access to all my variables (such as i)! ;)
Thread 1 running...
Thread 4 running...
Thread 3 running...
Thread 3: my stopping actions go here! Look, I have access to all my variables (such as i)! ;)
Thread 4: my stopping actions go here! Look, I have access to all my variables (such as i)! ;)
Thread 1: my stopping actions go here! Look, I have access to all my variables (such as i)! ;)
Exiting JVM...

This is a minimal solution I can see in your problem as you described it.

gthanop
  • 3,035
  • 2
  • 10
  • 27