在Java中是否有一个在进程结束时的方法?

huangapple go评论82阅读模式
英文:

Is there a when process ends method in java?

问题

I am trying to search when GTA5.exe ends. It launches with the "steam://rungameid" protocol, so I can't use the Process#waitFor(); method.

The method below checks if (currently) the process is running

public static boolean isProcessRunning(String processName) throws IOException {
    ProcessBuilder processBuilder = new ProcessBuilder("tasklist.exe");
    Process process = processBuilder.start();
    String tasksList = toString(process.getInputStream());

    return tasksList.contains(processName);
}

But what I want is something like

waitUntilProcessEnds(String processname) {
}

It could be

while (isProcessRunning) {
    Thread.sleep(1000);
}

And, as expected, my JavaFX app freezes.
If I try to run the while method in another Thread, my JavaFX App gives this error:

java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-6
    at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:279)
    at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:444)
    at javafx.scene.control.Dialog.show(Dialog.java:294)
    at com.thunderstorm.gta5.mod_installer.app.AppController$1$1.run(AppController.java:101)
    at java.lang.Thread.run(Thread.java:748)

I also tried this

Platform.runLater();

and this

Platform.setImplicitExit(false);

But nothing different...

How to fix this

英文:

I am trying to search when GTA5.exe ends. It launches with "steam://rungameid" protocol, so I can't use Process#waitFor(); method.

The method below checks if (currently) the process is running

public static boolean isProcessRunning(String processName) throws IOException {
        ProcessBuilder processBuilder = new ProcessBuilder("tasklist.exe");
        Process process = processBuilder.start();
        String tasksList = toString(process.getInputStream());

        return tasksList.contains(processName);
}

But what I want is something like

waitUntilProcessEnds(String processname) {
}

It could be

while (isProcessRunning) {
Thread.sleep(1000);
}

And, as expected, my JavaFX app freezes.
If I try to run the while method in another Thread, my JavaFX App gives this error:

java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-6
	at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:279)
	at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:444)
	at javafx.scene.control.Dialog.show(Dialog.java:294)
	at com.thunderstorm.gta5.mod_installer.app.AppController$1$1.run(AppController.java:101)
	at java.lang.Thread.run(Thread.java:748)

I also tried this

Platform.runLater();

and this

Platform.setImplicitExit(false);

But nothing different...

How to fix this

This question is edited

答案1

得分: 3

以下是翻译好的内容:

有一个 API,但需要 Java 9 或更新版本。然后,您可以顺利执行以下操作:

String name = "GTA5.exe";
ProcessHandle.allProcesses()
    .filter(ph -> ph.info().command()
        .filter(s -> s.regionMatches(true, s.length() - name.length(), name, 0, name.length()))
        .isPresent())
    .findAny()
    .ifPresentOrElse(ph -> {
        System.out.println("等待 " + ph.pid() + " " + ph.info().command().get());
        ph.onExit().thenRunAsync(() -> {
            // 您的实际操作
        }, Platform::runLater);
    }, () -> System.out.println("未找到匹配的进程"));

ProcessHandle.onExit() 返回一个 CompletableFuture,允许链接依赖动作,以在进程完成时执行。因此,您无需自己轮询进程。

此外,Platform.runLater(Runnable)Executor 接口的函数签名匹配,使我们能够使用 thenRunAsync(…, Platform::runLater) 来要求在进程退出后在 JavaFX 应用程序线程中执行依赖的操作(Runnable)。

英文:

There is an API, but it requires Java 9 or newer. Then, you can do it smoothly:

String name = "GTA5.exe";
ProcessHandle.allProcesses()
    .filter(ph -> ph.info().command()
        .filter(s -> s.regionMatches(true,s.length()-name.length(),name,0,name.length()))
        .isPresent())
    .findAny()
    .ifPresentOrElse(ph -> {
        System.out.println("Waiting for "+ph.pid()+" "+ph.info().command().get());
        ph.onExit().thenRunAsync(() -> {
            // your actual action
        }, Platform::runLater);
    }, () -> System.out.println("No matching process found"));

ProcessHandle.onExit() returns a CompletableFuture which allows to chain dependent actions, to be performed on the process’ completion. So you don’t need to poll the process yourself.

Further note that Platform.runLater(Runnable) matches the functional signature of the Executor interface which allows us to use thenRunAsync(…, Platform::runLater) to mandate that the dependent action (Runnable) should be executed in the JavaFX Application Thread, once the process has exited.

答案2

得分: 1

我认为你的设计还可以,但是你对线程有些混淆。首先,在你启动等待方法时,继续启动一个新的线程。

new Thread( () -> {
     waitUntilProcessEnds(processname);
     Platform.runLater( () -> callBackOnPlatformThread() );
}).start();

然后你需要:

public void callBackOnPlatformThread(){
    System.out.println("继续修改 fx 组件。");
}

这将在一个新线程上开始等待进程结束,因此你的 JavaFX 用户界面将继续响应。当进程完成时,它会在 JavaFX 平台线程上回调,这样你就可以修改组件。

这段代码没有检查线程是否已经启动,所以如果你有一个按钮来启动线程,可能会启动很多个线程。

英文:

I think your design is ok, but you're a bit confused by the threads. First when you start your wait method, go ahead and start a new Thread.

new Thread( ()->{
     waitUntilProcessEnds(processname);
     Platform.runLater( ()-> callBackOnPlatformThread() );
}).start();

Then you need.

public void callBackOnPlatformThread(){
    System.out.println("go ahead and modify fx components.");
}

This will start waiting for the process to end on a new thread, so your javafx UI will continue to be responsive. When it is finished, it calls back on the javafx Platform thread, so you can modify components.

This doesn't check if the thread has already been started, so if you have a button that starts the thread, you could start a bunch of them.

答案3

得分: 0

如果您想在 您的 应用程序结束时执行一些代码,可以添加一个关闭钩子:

Runtime.getRuntime().addShutdownHook(() -> { ... });

如果您想要等待外部进程结束,可以使用:

process.waitFor();

这会阻塞当前线程,直到外部进程退出。

英文:

What are you trying to achieve? If you want to execute some code when your application ends then you can add a shutdown hook:

Runtime.getRuntime().addShutdownHook(() -> { ... });

If you want to wait until the external process ends, then you can use:

process.waitFor()

This will block your current thread until the external process exits.

答案4

得分: -1

如果您的程序一开始没有创建该进程,则无法进行此操作。

Java不提供操作系统级别的功能,这些功能在底层操作系统中首先就不被提供。例如,在类Unix系统中,“等待进程退出”只能由进程祖先执行,而在Windows中,您必须拥有该进程的句柄,该句柄是从创建该进程中获得的。

您将不得不自己实现。创建一个线程,定期检查您要监视的进程是否存在,方法取决于该进程和您的操作环境。最坏的情况下,您将不得不派生一个“ps”命令(或类似命令)并解析输出。

关于JavaFX问题,我无法提供建议;那不是我的领域。

英文:

Not if your program didn't create the process in the first place.

Java does not provide operating-system level facilities that are not provided in the underlying OS in the first place. In Unix-like systems, for example, "wait for process exit" can only be executed by an ancestor of the process in question. In Windows, for another example, you have to possess a handle on the process, which you would have obtained from creating the process.

You'll have to roll your own. Create a thread which periodically checks for the existence of the process you are monitoring, by whatever means is suitable to that process and your operating environment. Worst-case you'll have to fork a 'ps' command (or similar) and parse the output.

I can't advise on the JavaFX issue; not my area.

huangapple
  • 本文由 发表于 2020年5月19日 18:20:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/61888657.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定