1

JVM 以这种方式处理 SIGPIPE 的原因是什么?

我本来期望的

java foo | head -10

public class Foo {
    public static void main(String[] args){
        Stream.iterate(0, n -> n + 1).forEach(System.out::println);
    }
}

在编写第 11 行时导致进程被终止,但事实并非如此。相反,似乎trouble在 PrintStream 上只设置了一个标志,可以通过System.out.checkError().

4

1 回答 1

3

发生的情况是 SIGPIPE 异常导致 IOException。

对于大多数OutputStreamWriter类,此异常通过“write”方法传播,并且必须由调用者处理。

但是,当您写入 System.out 时,您使用的是PrintStream,并且该类通过设计会照顾IOException您。正如javadoc所说:

APrintStream向另一个输出流添加了功能,即能够方便地打印各种数据值的表示。还提供了另外两个功能。与其他输出流不同, aPrintStream从不抛出IOException; 相反,异常情况只是设置一个可以通过该checkError方法测试的内部标志。

JVM 以这种方式处理 SIGPIPE 的原因是什么?

上面解释了正在发生的事情。“为什么”是......我猜......设计人员希望使其PrintStream易于用于调用者不想在每次调用中处理可能的典型用例。System.outIOException

不幸的是,没有优雅的解决方案:

  • 你可以打电话给checkError...
  • 您应该能够获取该FileDescriptor.out对象,并将其包装在一个新FileOutputStream对象中......并使用它而不是System.out.

请注意,没有强有力的保证 Java 应用程序只会将 10 行输出写入java foo | head -1. 应用程序很可能会提前写很多行,并且只有head在读取前 10 行之后才“看到”管道关闭。这适用于System.out(and checkError) 或 wrap FileDescriptor

于 2020-06-30T13:42:34.517 回答