非阻塞线程运行外部进程

8
我创建了一个Java GUI应用程序,作为许多低级外部进程的包装器。该实用程序可以正常工作,但是急需一项重大改进。
我希望我的外部进程以非阻塞方式运行,这将使我能够并行处理更多请求。简而言之,我想能够在生成数据时处理来自外部进程的数据。但是,似乎我的基本尝试检查外部进程是否仍在运行是阻塞的。
以下是我的ExternalProcess类的摘录。有关线程和阻塞的特定Java功能问题,请参见内联注释。
public void Execute()
{
    System.out.println("Starting thread ...\n");
    Runner = new Thread(this, "ExternalProcessTest");
    Runner.run();
    System.out.println("Ending thread ...\n");
}

public void run() 
{
    System.out.println("In run method ...\n");  // Debug purposes only. 
        // Show that we are in the run loop.
    try
    {
        // Execute string command SomeCommand as background process ...
        Process = Runtime.getRuntime().exec(SomeCommand);
        while(IsRunning())
        {
            // External process generates file IO.  I want to process these
            // files inside this loop.  For the purpose of this demo I have
            // removed all file processing to eliminate it as the cause
            // of blocking.  THIS ROUTINE STILL BLOCKS!
            Thread.sleep(1000);
        }
    }
    catch(Exception e)
    {
        System.out.println(e);
    }
    System.out.println("Exiting run method ...\n");  // Debug purposes only.
        // Show that we are exiting the run loop.
}

// Process (instantiated from Runtime.getRuntime().execute doesn't supports
// either fire-and-forget backgrounding (non-blocking) or you can wait for 
// the process to finish using the waitFor() method (blocking).  I want to
// be able to execute a non-blocking external process that I monitor via
// threading allowing me to process the external process file IO as it is
// created.  To facilitate this goal, I have created an isRunning() method
// that uses the exitValue() method.  If the process is still running, a 
// call to exitValue() will throw an IllegalThreadStateException exception.
// So I simply catch this execption to test if the background process is
// finished -- at which point I can stop processing file IO from the 
// process.  Is this the source of the blocking?  If so, is there another
// way to do this?
public boolean IsRunning()
{
    boolean isRunning = false;
    try
    {
        int exitVal = Process.exitValue();
    }
    catch(IllegalThreadStateException e)
    {
        isRunning = true;
    }
    return isRunning;
}
2个回答

10

在Thread上调用run()方法实际上不会启动新线程,请尝试使用Thread.start()代替。


1
哇,那真是相当愚蠢。但你是正确的。就是这样。非常感谢你,Mike! - Rodney
1
我自己也曾经多次中招。 :-) - Mike Deck

7
Runner = new Thread(this, "ExternalProcessTest");
Runner.run();
run()方法的命名有些误导性。因为Thread实现了Runnable接口,所以run()方法被公开暴露,但是当你想要启动一个新线程时,调用run()方法是不正确的。调用run()会导致线程代码在当前线程中运行。
你必须调用start()方法来实例化一个新线程:
Runner = new Thread(this, "ExternalProcessTest");
Runner.start();

谢谢John。这就解决了。感谢你抽出时间帮忙。 - Rodney

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接