java native Process timeout

前端 未结 6 1434
不思量自难忘°
不思量自难忘° 2020-11-27 14:31

At the moment I execute a native process using the following:

java.lang.Process process = Runtime.getRuntime().exec(command); 
int returnCode = process.waitF         


        
相关标签:
6条回答
  • 2020-11-27 15:02

    just modified a bit according to my requirement. time out is 10 seconds here. process is getting destroyed after 10 seconds if it is not exiting.

    public static void main(String arg[]) {
    
        try {
            Process p = Runtime.getRuntime().exec("\"C:/Program Files/VanDyke Software/SecureCRT/SecureCRT.exe\"");
            long now = System.currentTimeMillis(); 
            long timeoutInMillis = 1000L * 10; 
            long finish = now + timeoutInMillis; 
            while ( isAlive( p ) ) { 
                Thread.sleep( 10 ); 
                if ( System.currentTimeMillis() > finish ) {
                    p.destroy();
                }
            }
        } catch (Exception err) {
            err.printStackTrace();
        }
    }
    
    public static boolean isAlive( Process p ) {  
        try {  
            p.exitValue();  
            return false;  
        } catch (IllegalThreadStateException e) {  
            return true;  
        }  
    }  
    
    0 讨论(0)
  • 2020-11-27 15:04

    If you're using Java 8 or later (API 26 or later for Android) you could simply use the waitFor with timeout:

    Process p = ...
    if(!p.waitFor(1, TimeUnit.MINUTE)) {
        //timeout - kill the process. 
        p.destroy(); // consider using destroyForcibly instead
    }
    
    0 讨论(0)
  • 2020-11-27 15:08

    All other responses are correct but it can be made more robust and efficient using FutureTask.

    For example,

    private static final ExecutorService THREAD_POOL 
        = Executors.newCachedThreadPool();
    
    private static <T> T timedCall(Callable<T> c, long timeout, TimeUnit timeUnit)
        throws InterruptedException, ExecutionException, TimeoutException
    {
        FutureTask<T> task = new FutureTask<T>(c);
        THREAD_POOL.execute(task);
        return task.get(timeout, timeUnit);
    }
    
    final java.lang.Process[] process = new Process[1];
    try {
        int returnCode = timedCall(new Callable<Integer>() {
            public Integer call() throws Exception {
                process[0] = Runtime.getRuntime().exec(command); 
                return process[0].waitFor();
            }
        }, timeout, TimeUnit.SECONDS);
    } catch (TimeoutException e) {
        process[0].destroy();
        // Handle timeout here
    }
    

    If you do this repeatedly, the thread pool is more efficient because it caches the threads.

    0 讨论(0)
  • 2020-11-27 15:09

    This is how the Plexus CommandlineUtils does it:

    Process p;
    
    p = cl.execute();
    
    ...
    
    if ( timeoutInSeconds <= 0 )
    {
        returnValue = p.waitFor();
    }
    else
    {
        long now = System.currentTimeMillis();
        long timeoutInMillis = 1000L * timeoutInSeconds;
        long finish = now + timeoutInMillis;
        while ( isAlive( p ) && ( System.currentTimeMillis() < finish ) )
        {
            Thread.sleep( 10 );
        }
        if ( isAlive( p ) )
        {
            throw new InterruptedException( "Process timeout out after " + timeoutInSeconds + " seconds" );
        }
        returnValue = p.exitValue();
    }
    
    public static boolean isAlive( Process p ) {
        try
        {
            p.exitValue();
            return false;
        } catch (IllegalThreadStateException e) {
            return true;
        }
    }
    
    0 讨论(0)
  • 2020-11-27 15:20

    What about the Groovy way

    public void yourMethod() {
        ...
        Process process = new ProcessBuilder(...).start(); 
        //wait 5 secs or kill the process
        waitForOrKill(process, TimeUnit.SECONDS.toMillis(5));
        ...
    }
    
    public static void waitForOrKill(Process self, long numberOfMillis) {
        ProcessRunner runnable = new ProcessRunner(self);
        Thread thread = new Thread(runnable);
        thread.start();
        runnable.waitForOrKill(numberOfMillis);
    }
    
    protected static class ProcessRunner implements Runnable {
        Process process;
        private boolean finished;
    
        public ProcessRunner(Process process) {
            this.process = process;
        }
    
        public void run() {
            try {
                process.waitFor();
            } catch (InterruptedException e) {
                // Ignore
            }
            synchronized (this) {
                notifyAll();
                finished = true;
            }
        }
    
        public synchronized void waitForOrKill(long millis) {
            if (!finished) {
                try {
                    wait(millis);
                } catch (InterruptedException e) {
                    // Ignore
                }
                if (!finished) {
                    process.destroy();
                }
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-27 15:22

    You'd need a 2. thread that interrupts the thread that calls .waitFor(); Some non trivial synchronization will be needed to make it robust, but the basics are:

    TimeoutThread:

     Thread.sleep(timeout);
     processThread.interrupt();
    

    ProcessThread:

      try {
          proc.waitFor(); 
        } catch (InterruptedException e) {
           proc.destroy();
        }
    
    0 讨论(0)
提交回复
热议问题