【问题标题】:Can you remap system.in , system.out and system.err to Java threads?您可以将 system.in 、 system.out 和 system.err 重新映射到 Java 线程吗?
【发布时间】:2011-06-26 11:55:15
【问题描述】:

我有一些使用 stdio 进行输入和输出的旧 C++ 代码。该代码还通过分叉生成新进程。它将 stdio 重新映射到每个新进程,以便每个会话获取其各自的数据。

我正在研究使用 Java 中的线程来创建子进程。但是,在找出如何在创建时将 System.inSystem.outSystem.err 重新映射到子线程时,我陷入了困境。

如果可能的话,谁能指出我正确的方向?

【问题讨论】:

  • 线程与进程不同,你不能用它们“创建子进程”。它们共享相同的数据,包括 stdio 的东西。如果从一个线程重新映射它,它将影响所有线程。
  • 我的意思是 java 似乎没有诸如 fork() 之类的方法,所以我想知道是否可以使用线程而不是进程来执行任务。也许一个 .exec() 是要走的路,但是,我可以用同样的方式重新映射 stdio 吗?
  • 有同样情况的朋友可以看看这个答案来寻找灵感:stackoverflow.com/a/15526391/363573.

标签: java multithreading fork stdio


【解决方案1】:

简单的答案不是写你的代码直接访问 System.out/in/err。而是将InputStream 和两个OutputStreams 传递给对象的构造函数。然后该对象直接与这些对象一起工作,而不依赖于它们实际映射到的对象。要访问print()println(),您需要将OutputStream 传递给PrintStream 的构造函数。

然后根据您实际想要做的,您可以使用 System.out 或 FileOutputStream 调用构造函数。

【讨论】:

    【解决方案2】:

    生成线程与生成进程不同。当您在 java(和 c++)中生成线程时,它与生成器共享相同的内存空间(即它们共享相同的 sdio 流)。如果你想在 java 中生成一个新的进程,你可以使用 Runtime.exec() 然后你必须手动将 io 传输到新进程中,java 不支持跨进程共享 io 流边界。

    【讨论】:

      【解决方案3】:

      Java 没有 fork(),但它有 ProcessBuilder 和 Runtime.exec() 用于启动新进程(Process 类的对象)。您可以将其视为 fork()/exec() 对,但无法在 dup2() 之间执行某些操作。这意味着您不能重定向子进程的 stdio,但您可以使用相应的 Process 方法,或者准确地说,输入/输出流的相应方法,将某些内容显式写入其 stdin 并从其 stdout 和 stderr 读取由 Process 类的 getInputStream()/getOutputStream()/getErrorStream() 方法返回。如果您想拥有进程而不是线程,这可能是有效的解决方法。

      如果你想使用线程,那么它们都共享同一个 stdio。您可以重定向它,但这将毫无意义,因为重定向会影响所有线程。您可以通过使用自定义 InputStream/OutputStream 实现的线程对 IPC 进行某种模仿,或者您可能希望查看 PipedInputStream/PipedOutputStream 对。这些实际上可用于设置 IPC 管道之类的东西,可能与 BufferedInputStream/BufferedOutputStream 结合使用以避免过度阻塞。

      【讨论】:

      • 产卵过程似乎是要走的路。只是担心内存使用,这就是为什么我仍然热衷于寻找线程解决方案,我想这取决于开销。谢谢。
      • @andicrook,是的,Java 有时会占用大量内存。我不会求助于使用进程,除非我想要一个真正强大的应用程序,即使其中一个子进程崩溃也可以继续运行。线程有时可能很难调试,但一旦掌握了它,它们通常更易于使用且效率更高,尤其是在内存方面。
      【解决方案4】:

      我建议使用单独的进程,或者为每个线程显式分配一个 PrintStream。

      但是,即使每个线程看到 System.out 的相同对象,也可以将写入 System.out 的内容转发到每个线程的不同位置。在您的启动代码中,您将使用自定义 PrintStream 调用 System.setOut(PrintStream)。这个 PrintStream 将覆盖所有的 print 和 write 方法。在这些方法中,它会使用 InheritableThreadLocal 查找线程的 PrintStream 并将方法调用转发给它。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-12
        • 1970-01-01
        • 2013-02-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多