【问题标题】:ProcessBuilder is holding a lock to the spawned processProcessBuilder 正在锁定生成的进程
【发布时间】:2013-10-30 11:03:26
【问题描述】:

我正在从我的程序中调用一个外部 JAVA 进程。我正在使用生成的进程生成的输出,如下所示:

DataInputStream dis = new DataInputStream(new BufferedInputStream(myProcess.getInputStream()));

从一个线程我正在执行以下操作:

            while (dis.available() != 0) 
            {                   

                firstMesg = dis.readLine();


                if(firstMesg != null) 
                {
                    // processing with the message
                    //System.out.println(firstMesg);    
                }                                                                       
            } 


            try 
            {
                Thread.currentThread().sleep(SLEEP_TIME);
            }
            catch(Throwable e) 
            {
            }

我给 SLEEP_TIME 大约 1 分钟,一切正常。突然,对于某个特定设置,我发现 Sys out (System.out.println) 从生成的过程中花费了非常长的时间。

谁能指出发生了什么事?这两个过程必须是独立的。然而,调用者正在从被调用的进程中读取数据。但是在被调用的进程正在写入的地方,缓冲区应该很大。因此,它不可能被阻止。

我可以在 ProcessBuilder Java 文档中看到这一点:

父进程使用这些流(#getInputStream()、#getErrorStream())向子进程提供输入并从子进程获取输出。因为一些原生平台 只为标准输入和输出流提供有限的缓冲区大小,不能及时写入输入流或读取子进程的输出流可能 导致子进程阻塞,甚至死锁。

【问题讨论】:

  • 外部是做什么的?正如dis.readLine(); 上的线程块,您必须检查外部进程中发生的情况。
  • 我在一个线程上执行此操作并不断检查调用的进程产生了什么。中间有睡眠。
  • 我想到了一个外部进程——在你调用它时调用了一个。无论如何,要么您在主应用程序中等待太久而阻塞了外部进程,要么进程在生成输出时遇到了一些麻烦。总而言之,你不应该那样等待,但就像布赖恩写的那样,继续从进程中读取(这个操作会尽可能多地为你阻塞)。获取有关流和流操作的一些信息。

标签: java multithreading process


【解决方案1】:

看看NuProcess 库,它为衍生进程提供了非阻塞(异步)I/O。 免责声明:我是 NuProcess 的作者

【讨论】:

    【解决方案2】:

    您需要持续阅读,而不是阅读立即可用的内容然后睡觉。注意(也)你应该对stdout stderr做同样的事情。

    有关使用StreamGobbler 实现此目的的信息,请参阅this question

    【讨论】:

    • 如果我继续读取输出,那么我会被阻塞。所以我正在阅读可用的内容,然后去睡觉并循环播放。
    • 是的,你被屏蔽了。但是你在你产生的线程上被阻止了。 大多数时候你的 stdout 和 stderr 消耗线程将被阻塞,等待你的进程输出一些东西(除非你的进程确实非常冗长)
    • 我认为你误解了这个问题。调用程序进程未被阻塞。被调用的进程被阻塞。
    【解决方案3】:

    这是我在您的情况下所期望的行为。如果一个进程产生stdout(或就此而言的stderr)输出,它不能永远继续这样做,而没有实际对该输出做一些事情。当您的进程产生输出时,它将被操作系统缓冲,直到该缓冲区已满。您的进程从缓冲区中读取,再次腾出更多空间。如果您的程序没有读取,那么缓冲区将在某个时候填满,操作系统将暂停该进程,直到空间可用。

    在您的 Java 进程中创建一个线程来读取 STDOUT,并在需要时将其缓冲在 Java 端。另一方面,您可能应该在它到达时对其进行处理,因为它听起来有很多。

    编辑:基于 cmets... 和其他东西....

    DataInputStream.readLine() 已弃用,请勿使用。

    而不是有一个while循环:

    while (dis.available() != 0) {...}
    

    while ((line = br.readLine()) != null) { ....}
    

    其中brnew BufferedReader(new InputStreamReader(myProcess.getInputStream()))

    【讨论】:

    • 我已经在在一个线程上执行此操作,并不断检查调用的进程产生了什么。中间有睡眠
    • 他并没有持续检查进程……他只检查直到没有可用的第一刻。 available() 将在没有任何内容时返回0,这可能至少会在进程启动时的前几分之一秒内发生......因此,没有从 STDOUT 中读取任何内容。考虑在 while 循环中使用其他一些条件。
    • 添加了一些说明。
    猜你喜欢
    • 1970-01-01
    • 2014-07-06
    • 2021-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多