6

I have three classes say alpha, beta, gamma and each of the three classes has a main method.

Both alpha and beta classes have, inside their main method, a try...catch...finally block like:

public class alpha{

    public static void main(String[] args){
        try{
            Do something;
        }catch(Exception ex){
            ex.printStackTrace();
        }
        finally{
            System.exit(0);
        }
    }
}


public class beta{

    public static void main(String[] args){
        try{
            Do something;
         }catch(Exception ex){
            ex.printStackTrace();
        }
        finally{
            System.exit(0);
        }
    }
}

Now in gamma class i call main methods of alpha and beta classes to run continuously like below

public gamma{

    public static void main(String[] args) {
        try {
            alpha.main(arg);
            beta.main(arg1);
        } catch (Exception e) {
            e.printStackTrace();
        }
}

The problem is that the code beta.main(arg1) is never reached due to the System.exit(0) inside the alpha class's finally block. Since alpha and beta are standalone applications when they executed separately they should terminate the service at the end of program. So now this there any way to reach the beta.main(arg1) line without much changing the actual functionality of alpha and beta classes.

Kindly let me know if you need further details. Thanks in advance...

Mike Samuel
  • 118,113
  • 30
  • 216
  • 245
coolgokul
  • 257
  • 1
  • 7
  • 18
  • 1
    possible duplicate of [Preventing System.exit() from API](http://stackoverflow.com/questions/5401281/preventing-system-exit-from-api) – Mat Jan 04 '12 at 16:56

4 Answers4

4

In such case, shutdown hook can be used:

public class Gamma{

    public static void main(String[] args) {
        try {
        Thread hook = new Thread() { public void run() { Beta.main(args); } };
            hook.setDaemon(true);
            Runtime.getRuntime().addShutdownHook(hook);
            Alpha.main(args);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
Vlad
  • 1,723
  • 12
  • 16
  • Nice. I had never though of using shutdown hooks as a continuation mechanism. – Mike Samuel Jan 04 '12 at 17:08
  • Hi Vlad...I have one more query... how to end service of your code when both alpha.main(args) and beta.main(args) executed.?? Thanks in advance... – coolgokul Jan 04 '12 at 17:19
  • Your program executes so perfectly as like i desired but only one problem is that the gamma class should end the service ( same like System.exit(0)) once its executed your syntax. Can you able to help on this....? Thanks... – coolgokul Jan 04 '12 at 17:31
  • Good catch... I've updated the code. The hook thread should be daemon to not block the final System.exit(0). – Vlad Jan 04 '12 at 17:41
  • Hi Vlad, thanks for your reply... some how the program doesn't terminate even after setting daemon as true. is your code missing something.. pls help me out. Thanks... – coolgokul Jan 04 '12 at 19:20
  • Unfortunately, my "great" idea didn't work out because it's not possible to invoke System.exit from a shutdown hook thread as it is already executed from the previous System.exit (because of this line `synchronized (Shutdown.class)` in Shutdown.exit). So I'd suggest going with the solution by @MikeSamuel, or run alpha and beta classes as external processes (see `ProcessBuilder` and `Runtime.exec(..)`). – Vlad Jan 04 '12 at 19:49
2

(Ideally, nothing that is part of a module's public API should ever do anything that calls exit, and the main method of a class should just be a small shim that invokes something else that does the real work before producing the proper exit code.)

That said, if you want to prevent System.exit, you can register a SecurityManager that converts calls to System.exit into SecurityExceptions or Errors.

System.exit:

throws

SecurityException - if a security manager exists and its checkExit method doesn't allow exit with the specified status.

Something like

System.setSecurityManager(new SecurityManager() {
  @Override
  public void checkExit(int exitCode) throws SecurityException {
    throw new SecurityException("stop that");
  }
});

Then the method which is calling main methods can just catch and suppress that SecurityException. You could make it more robust by creating your own ExitCalledError and throwing that instead and only suppressing that.

I find this very useful for preventing unit-test runners from spuriously reporting success when the test runner is exited by code under test with a zero exit code.

Community
  • 1
  • 1
Mike Samuel
  • 118,113
  • 30
  • 216
  • 245
  • Hm. I can't decide what I think about this -- I hate to use the SecurityManager to do non-security things, but this is a sort of elegant hack. – Charlie Martin Jan 04 '12 at 16:58
  • 1
    @CharlieMartin, I agree that it's a hack. It is fairly robust as hacks go though, and some concerns, the reliability of test runner feedback, warrant it IMO. There are of course problems though -- the mere presence of a `SecurityManager` can tickle subtle bugs in library code and can affect the way the VM optimizes things. – Mike Samuel Jan 04 '12 at 17:05
  • Well, and I upvoted it. Still haven't decided what I think of it though. – Charlie Martin Jan 04 '12 at 22:12
1

Really, the only solution is to get rid of the System.exit() call. This is why System.exit() is evil. A good way to replace them is by throwing an exception -- you can add an exception handler to the system (look into adding them to ThreadGroups to add one for every exception path) and then decide what you want to do.

Charlie Martin
  • 110,348
  • 25
  • 193
  • 263
0

System.exit(0) terminates the currently running Java Virtual Machine. It closes all application on the VM, not just the application which calls System.exit(0). You need to think alternative for your functionality. Here is a link about it. System.exit usage

Mike Samuel
  • 118,113
  • 30
  • 216
  • 245
kosa
  • 65,990
  • 13
  • 130
  • 167