2016-07-01 16 views
1

コマンドウィンドウで実行されるアプリケーションがあります。ユーザーが/quitと入力したときにこれを検出し、それぞれquit()メソッドを実行するScannerがあります。コンソールが閉じるときにメソッドを呼び出す(Java)

これは完全に機能しますが、ユーザーが/quitを入力せずにコンソールを閉じても、quit()を実行するかどうかを判断する方法はありますか?

+1

は、[シャットダウンフック](https://docs.oracle.com/javase/7/docs/を追加api/java/lang/Runtime.html#addShutdownHook(java.lang.Thread))? – shmosel

答えて

1

シャットダウンフックを使用してください。依然として100%保証されているわけではありませんが、シャットダウンを試みるための最良の方法です。一般的に言えば、シャットダウンフックでは絶対最小限に抑える必要があります。リソースを閉じたり、いくつかのロギングステートメントやprintstatementsを削除しますが、時間がかかりません。

あなたのコードに一致するように、ここで見つけた回答をDetecting when a Java application closesロバートにコピーして少し修正しました。このコードは、quit()を呼び出す権限があるどこかに置かなければなりません。これは一度だけ呼び出すべきですが、全体のプロセスの早い段階で呼び出してください。

Runtime.getRuntime().addShutdownHook(new Thread() { 

    @Override 
    public void run() { 
     quit(); 
    } 

}); 

シャットダウンフックが何をしているかの詳細については、この質問を参照してください:Useful example of a shutdown hook in Java?

シャットダウンフックをと呼ばれることはありませんでしょうときに詳細については、この質問の受け入れ答えを参照してくださいshutdown hook vs finalizer method

quit()TLで作業する必要がある時間の情報については、この質問を参照してください。How long does the JVM allow shutdown hooks to run before calling halt?

+0

ええと、ウィンドウコマンドプロンプトを閉じると、何かをする前に閉じてしまうようです...私はそこに 'Thread.sleep()'を入れて、それはただちに閉じます。何かをする前に他の答えがあるかどうかわかります。しかし、ありがとう! = D @Jeutnarg – criticaldiamonds

+0

OSがどのようにプロセスを殺すかによって、何かをする機会が得られるかもしれません。これは、シャットダウンフックが信頼できない理由です。 –

+0

@criticaldiamondsあなたの礼儀が私に動機を与えてくれました - 私の他の答えを見てください – Jeutnarg

0

これはあなたのプロを捕まえるのに、グラムの出口。意図的にこの方法を壊すことができるいくつかの方法があり、OSが誤ってそれを破る可能性があるいくつかの揺れの部屋があります。それが私が「危険な人」と言った理由です。

Bodyguardという1つのクラスを作成します。このクラスは独自のプロセスIDを特定し、processidを入力としてRealProgramを実行します。 Bodyguardは、RealProgramがシャットダウンするまで待ってから終了します。その間、RealProgramはBodyguardのプロセスがまだ実行中であることを監視して確認します。ボディーガードが死亡したと判断した場合、メインループを終了し、終了する前にquit()を呼び出します。

私はこれをWindows 10でテストし、Java 8を実行して、eclipseデバッガからBodyguardを強制終了しました。ボディーガードが殺されると、quit()を呼び出した後にRealProgramがシャットダウンします。リアルプログラムが殺されると、ボディガードも終了します。

コードで遊びたいと思うので、ライターなどのデバッグ要素のいくつかを残しました。

Iクレジット:Windowsからの実行中のプロセスを取得する方法で二JVM

  • this external pageを開始する方法のコードでプロセスID
  • this questionを取得するためのコードと

    用心棒クラス:

    package so_38154756; 
    
    import java.lang.reflect.InvocationTargetException; 
    
    public class Bodyguard { 
    
        public static void main(String[] args){ 
         Bodyguard lamb = new Bodyguard(); 
         lamb.initiateSacrifice(); 
        } 
    
        private void initiateSacrifice() { 
         try{ 
          int ownPid = getPID(); 
          runRealProgram(ownPid); 
         } catch(Exception e){ 
          System.out.println("Sorry, this isn't working."); 
         } 
        } 
    
        private int getPID() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { 
         java.lang.management.RuntimeMXBean runtime = java.lang.management.ManagementFactory.getRuntimeMXBean(); 
         java.lang.reflect.Field jvm = runtime.getClass().getDeclaredField("jvm"); 
         jvm.setAccessible(true); 
         sun.management.VMManagement mgmt = (sun.management.VMManagement) jvm.get(runtime); 
         java.lang.reflect.Method pid_method = mgmt.getClass().getDeclaredMethod("getProcessId"); 
         pid_method.setAccessible(true); 
         int pid = (Integer) pid_method.invoke(mgmt); 
         return pid; 
        } 
    
        private void runRealProgram(int ownPid) throws Exception { 
         String separator = System.getProperty("file.separator"); 
         String classpath = System.getProperty("java.class.path"); 
         String path = System.getProperty("java.home") + separator + "bin" + separator + "java"; 
         ProcessBuilder processBuilder = new ProcessBuilder(path, "-cp", classpath, RealProgram.class.getName(), Integer.valueOf(ownPid).toString()); 
         Process process = processBuilder.start(); 
         process.waitFor();//will wait forever, but will close when the RealProgram closes 
        } 
    
    } 
    

    とRealProgramクラス:

    package so_38154756; 
    
    import java.io.BufferedReader; 
    import java.io.File; 
    import java.io.FileNotFoundException; 
    import java.io.InputStreamReader; 
    import java.io.PrintWriter; 
    import java.util.regex.Pattern; 
    
    public class RealProgram { 
    
        private Integer bodyguardPID; 
        private PrintWriter writer; 
    
        public RealProgram(Integer bodyguardPID, PrintWriter writer) { 
         this.bodyguardPID = bodyguardPID; 
         this.writer = writer; 
        } 
    
        public static void main(String[] args){ 
         Integer sacrificialPID = Integer.parseInt(args[0]); 
         try { 
          PrintWriter writer = new PrintWriter(new File("output.txt")); 
          RealProgram rp = new RealProgram(sacrificialPID, writer); 
          writer.println("Past Constructor"); 
          rp.checkToSeeIfBodyguardLives(); 
          writer.println("Bodyguard had died"); 
          writer.close();//yes, yes, this could be slightly prettier with Java 8's try-with-resources 
         } catch (FileNotFoundException e) { 
          e.printStackTrace(); 
         } 
        } 
    
        private void checkToSeeIfBodyguardLives() { 
         while(true){ 
          try { Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}//I wait because I was debugging - you may find it wise to not wait 
          //do whatever it is you're doing 
          if(!isBodyguardAlive()){ 
           quit(); 
           break; 
          } 
         } 
        } 
    
        private boolean isBodyguardAlive() { 
         try { 
          String process; 
          Pattern pattern = Pattern.compile(".*\\\""+bodyguardPID+"\\\".*");//Windows - have tested 
          //you'll have to figure out your own different pattern for linux - possible source for editing 
          writer.println("Searching for PID of "+bodyguardPID); 
          //Process p = Runtime.getRuntime().exec("ps -few"); - Linux - haven't tested - again, possible source for editing 
          Process p = Runtime.getRuntime().exec(System.getenv("windir") +"\\system32\\"+"tasklist.exe /fo csv /nh");//Windows - have tested 
          BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream())); 
          while ((process = input.readLine()) != null) { 
           if(pattern.matcher(process).matches()){ 
            return true; 
           } 
          } 
          input.close(); 
         } catch (Exception err) { 
          err.printStackTrace(); 
         } 
         return false; 
        } 
    
        private void quit(){ 
         writer.println("Detected Bodyguard has died"); 
        } 
    } 
    
  • 関連する問題