Process Builder and Process in Java - how to execu

2020-03-03 07:07发布

I need to execute an external batch file in java with a specific timeout. which means that if the batch execution take longer than specified timeout, i need to cancel the execution.

here is a sample code that i wrote:

public static void main(String[] args) throws IOException, InterruptedException {
    ProcessBuilder p = new ProcessBuilder("c:\\wait.bat", "25");  // batch file execution will take 25 seconds.
    final long l = System.currentTimeMillis();
    System.out.println("starting..." + (System.currentTimeMillis() - l));
    final Process command = p.start();
    System.out.println("started..." + (System.currentTimeMillis() - l));

    Timer t = new Timer();
    t.schedule(new TimerTask() {

        @Override
        public void run() {
            command.destroy();
        }
    }, 5000);   // it will kill the process after 5 seconds (if it's not finished yet).
    int i = command.waitFor();
    t.cancel();
    System.out.println("done..." + (System.currentTimeMillis() - l));
    System.out.println("result : " + i);

    System.out.println("Really Done..." + (System.currentTimeMillis() - l));
}

the batch file "wait.bat" is something like this:

@echo off
echo starting the process...
@ping 127.0.0.1 -n 2 -w 1000 > nul
@ping 127.0.0.1 -n %1% -w 1000> nul
echo process finished succesfully
@echo on

As you see in the code, batch file will take 25 seconds to finish (first line in main method) and the Timer will destroy the command after 5 seconds.

here is the output of my code:

starting...0
started...0
done...5000
result : 1
Really Done...5000
BUILD SUCCESSFUL (total time: 25 seconds)

as you see in output, the last line ("Really Done...") is executed in 5th second but the application is finished after 25 seconds.

my question is that : even though i called the destroy method in my timer, why jvm still waiting for the process to be finished ?

标签: java process
3条回答
霸刀☆藐视天下
2楼-- · 2020-03-03 07:08

If you use Unix/Linux, then write a wrapper bash shell script to interrupt an external command by timeout, then call the wrapper from Java.

The wrapper script looks like

#!/bin/bash
timeout 60 <your command>

You can detect if timeout expired by checking the script exit code which is 124 in case of timeout

See

man timeout

查看更多
够拽才男人
3楼-- · 2020-03-03 07:19

I could be a problem with the cancel method of the timer. try to start the timer as daemon thread.

Timer t = new Timer(true);
查看更多
Juvenile、少年°
4楼-- · 2020-03-03 07:22

It is a bug in Java's Process.destroy() implementation on Windows. The problem is that the batch-script (or its executing shell) is killed, but does not kill its own child processes (the ping here). Thus, ping is still running after the .destroy(), and also after the .waitFor(). But somehow the VM still waits for the ping to finish before finishing itself.

It seems there is nothing you can do here from the Java side to really kill the ping reliably.

You may think about using start (in your batch script or outside) to invoke your ping as a separate process.

(See also this previous discussion.)

Or change to a unix-like operation system.

查看更多
登录 后发表回答