簡體   English   中英

如何從 Java 程序啟動完全獨立的進程?

[英]How do I launch a completely independent process from a Java program?

我正在開發一個用 Java 編寫的程序,對於某些操作,它使用用戶配置的命令行啟動外部程序。 目前它使用Runtime.exec()並且不保留Process引用(啟動的程序是文本編輯器或存檔實用程序,因此不需要系統輸入/輸出/錯誤流)。

但這有一個小問題,即當 Java 程序退出時,它不會真正退出,直到所有啟動的程序都退出。

如果啟動的程序完全獨立於啟動它們的 JVM,我會非常喜歡它。

目標操作系統有多種,Windows、Linux 和 Mac 是最少的,但任何帶有 JVM 的 GUI 系統都是真正需要的(因此實際命令行的用戶可配置性)。

有誰知道如何使啟動的程序完全獨立於 JVM 執行?


編輯回復評論

啟動代碼如下。 代碼可能會啟動位於特定行和列的編輯器,也可能會啟動存檔查看器。 配置的命令行中的引用值被視為 ECMA-262 編碼,並被解碼並去除引號以形成所需的 exec 參數。

發射發生在 EDT 上。

static Throwable launch(String cmd, File fil, int lin, int col) throws Throwable {
    String frs[][]={
        { "$FILE$"  ,fil.getAbsolutePath().replace('\\','/') },
        { "$LINE$"  ,(lin>0 ? Integer.toString(lin) : "") },
        { "$COLUMN$",(col>0 ? Integer.toString(col) : "") },
        };
    String[] arr; // array of parsed tokens (exec(cmd) does not handle quoted values)

    cmd=TextUtil.replace(cmd,frs,true,"$$","$");
    arr=(String[])ArrayUtil.removeNulls(TextUtil.stringComponents(cmd,' ',-1,true,true,true));
    for(int xa=0; xa<arr.length; xa++) {
        if(TextUtil.isQuoted(arr[xa],true)) {
            arr[xa]=TextDecode.ecma262(TextUtil.stripQuotes(arr[xa]));
            }
        }
    log.println("Launching: "+cmd);
    Runtime.getRuntime().exec(arr);
    return null;
    }

這似乎只有在從我的 IDE 啟動程序時才會發生。 我正在關閉這個問題,因為該問題僅存在於我的開發環境中; 這在生產中不是問題 從其中一個答案中的測試程序以及我進行的進一步測試來看,我很滿意這不是任何平台上該程序的任何用戶都會看到的問題。

您的進程之間存在父子關系,您必須打破這種關系。 對於 Windows,您可以嘗試:

Runtime.getRuntime().exec("cmd /c start editor.exe");

對於 Linux,該進程似乎無論如何都可以獨立運行,不需要 nohup。 我用gvimmidoriacroread試過了。

import java.io.IOException;
public class Exec {
    public static void main(String[] args) {
        try {
            Runtime.getRuntime().exec("/usr/bin/acroread");
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("Finished");
    }
}

我認為以獨立於平台的方式使用Runtime.exec是不可能的。

對於 POSIX 兼容系統:

 Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c", "your command"}).waitFor();

我有一些觀察可以幫助其他面臨類似問題的人。

當您使用 Runtime.getRuntime().exec() 然后忽略返回的 java.lang.Process 句柄時(如原始海報中的代碼),啟動的進程可能會掛起。

我在 Windows 環境中遇到過這個問題,並將問題追溯到 stdout 和 stderr 流。 如果啟動的應用程序正在寫入這些流,並且這些流的緩沖區已滿,則啟動的應用程序在嘗試寫入流時可能會掛起。 解決方法是:

  1. 捕獲進程句柄並不斷清空流 - 但是如果您想在啟動進程后立即終止 java 應用程序,那么這不是一個可行的解決方案
  2. 作為cmd /c <<process>>執行進程調用(這僅適用於 Windows 環境)。
  3. 使用' command > nul 2>&1 '為進程命令添加后綴並將stdout和stderr流重定向到nul

如果您發布重現問題所需的最少代碼的測試部分,這可能會有所幫助。 我在 Windows 和 Linux 系統上測試了以下代碼。

public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws Exception {
        Runtime.getRuntime().exec(args[0]);
    }
}

並在 Linux 上進行了以下測試:

java -jar JustForTesting.jar /home/monceaux/Desktop/__TMP/test.sh

其中 test.sh 看起來像:

#!/bin/bash
ping -i 20 localhost

以及Linux上的這個:

java -jar JustForTesting.jar gedit

並在 Windows 上對此進行了測試:

java -jar JustForTesting.jar notepad.exe

所有這些都啟動了他們想要的程序,但 Java 應用程序退出沒有問題。 我有java -version報告的 Sun JVM 的以下版本:

  • 視窗:1.6.0_13-b03
  • Linux:1.6.0_10-b33

我還沒有機會在我的 Mac 上進行測試。 也許在您的項目中與其他代碼發生了一些可能不清楚的交互。 您可能想試試這個測試應用程序,看看結果如何。

您想在后台啟動程序,並將其與父程序分開。 我會考慮nohup(1)

我嘗試了這里提到的所有內容,但沒有成功。 即使使用 cmd /c start 和重定向流 tu nul,主父 Java 進程也無法退出,直到子線程退出。

對我來說只有一個可靠的解決方案是這樣的:

try {
    Runtime.getRuntime().exec("psexec -i cmd /c start cmd.cmd");
}
catch (Exception e) {
    // handle it
}

我知道這還不清楚,但是來自 SysInternals 的這個小實用程序非常有用且經過驗證。 是鏈接。

我懷疑這需要一個實際的流程分支。 基本上,你想要的 C 等價物是:

pid_t id = fork();
if(id == 0)
  system(command_line);

問題是你不能在純 Java 中執行 fork() 。 我會做的是:

Thread t = new Thread(new Runnable()
{
    public void run()
    {
      try
      {
          Runtime.getRuntime().exec(command);
      }
      catch(IOException e)
      {           
          // Handle error.
          e.printStackTrace();
      }
    }
});
t.start();

這樣 JVM 仍然不會退出,但不會有 GUI,只會保留有限的內存占用。

我能想到的一種方法是使用 Runtime.addShutdownHook 注冊一個終止所有進程的線程(當然,您需要將進程對象保留在某處)。

關閉掛鈎僅在 JVM 退出時調用,因此它應該可以正常工作。

有點黑客但有效。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM