JVM 未在 SIGPIPE 上终止

JVM not killed on SIGPIPE

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行时导致进程被杀死,但事实并非如此。相反,PrintStream 似乎只设置了一个 trouble 标志,可以通过 System.out.checkError().

检查

SIGPIPE 异常导致 IOException。

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

但是,当您写入 System.out 时,您使用的是 PrintStream,而 class 设计 负责你的IOException。正如 javadoc 所说:

A PrintStream adds functionality to another output stream, namely the ability to print representations of various data values conveniently. Two other features are provided as well. Unlike other output streams, a PrintStream never throws an IOException; instead, exceptional situations merely set an internal flag that can be tested via the checkError method.

What is the reason for the JVM handling SIGPIPE the way it does?

以上解释了正在发生的事情。 “为什么”是……我猜……设计师想让 PrintStream 易于用于 System.out 典型 用例,其中调用者不想在每次调用时都处理可能的 IOException

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

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

请注意,无法保证 Java 应用程序只会在 java foo | head -1 中写入 10 行输出。应用程序很可能会预写很多行,并且在 head 开始阅读其中的前 10 行之后才“看到”管道关闭。这适用于 System.out(和 checkError)或者如果你换行 FileDescriptor.