工作中遇到需要对JDK的Process类做一些拓展,以便在开AI组的Python工作进程时,从stdout、stderr、stdin三种标准输入输出流外的自定义pipe流传递参数
JDK似乎没给开自定义pipe通信的方式,如果要自定义pipe,就得写native代码,但如此就无法保证跨平台了。最终索性直接将AI组的进程单独容器化,基于HTTP做了通信。
PipedInputStream
和PipedOutputStream
也只能用于线程间通信。
虽然最后没有成功,但看到了JDK里一些有意思的。
在看Open JDK的Process类代码时,发现一段涉及平台特定功能的代码,这对Java服务端开发者来说很罕见。
对Java服务端开发者来说,JDK&JVM往往会直接确保开发者写的所有代码都是各平台通用的,因此Java开发者一般很少关注平台特性。
比如Windows中开子线程的API CreateThread;Linux、MacOS等类Unix系统API则是pthread_create。JVM直接帮我们屏蔽掉了平台API差异,直接在Java代码里区分平台的情况少之又少。
今天看到的这段代码,说明了如何在Java中获取系统类型。
void initStreams(int[] fds, boolean forceNullOutputStream) throws IOException {
switch (OperatingSystem.current()) {
case LINUX:
case MACOS:
stdin = (fds[0] == -1) ?
ProcessBuilder.NullOutputStream.INSTANCE :
new ProcessPipeOutputStream(fds[0]);
stdout = (fds[1] == -1 || forceNullOutputStream) ?
ProcessBuilder.NullInputStream.INSTANCE :
new ProcessPipeInputStream(fds[1]);
stderr = (fds[2] == -1) ?
ProcessBuilder.NullInputStream.INSTANCE :
new ProcessPipeInputStream(fds[2]);
ProcessHandleImpl.completion(pid, true).handle((exitcode, throwable) -> {
lock.lock();
try {
this.exitcode = (exitcode == null) ? -1 : exitcode.intValue();
this.hasExited = true;
condition.signalAll();
} finally {
lock.unlock();
}
if (stdout instanceof ProcessPipeInputStream)
((ProcessPipeInputStream) stdout).processExited();
if (stderr instanceof ProcessPipeInputStream)
((ProcessPipeInputStream) stderr).processExited();
if (stdin instanceof ProcessPipeOutputStream)
((ProcessPipeOutputStream) stdin).processExited();
return null;
});
break;
case AIX:
stdin = (fds[0] == -1) ?
ProcessBuilder.NullOutputStream.INSTANCE :
new ProcessPipeOutputStream(fds[0]);
stdout = (fds[1] == -1 || forceNullOutputStream) ?
ProcessBuilder.NullInputStream.INSTANCE :
new DeferredCloseProcessPipeInputStream(fds[1]);
stderr = (fds[2] == -1) ?
ProcessBuilder.NullInputStream.INSTANCE :
new DeferredCloseProcessPipeInputStream(fds[2]);
ProcessHandleImpl.completion(pid, true).handle((exitcode, throwable) -> {
lock.lock();
try {
this.exitcode = (exitcode == null) ? -1 : exitcode.intValue();
this.hasExited = true;
condition.signalAll();
} finally {
lock.unlock();
}
if (stdout instanceof DeferredCloseProcessPipeInputStream)
((DeferredCloseProcessPipeInputStream) stdout).processExited();
if (stderr instanceof DeferredCloseProcessPipeInputStream)
((DeferredCloseProcessPipeInputStream) stderr).processExited();
if (stdin instanceof ProcessPipeOutputStream)
((ProcessPipeOutputStream) stdin).processExited();
return null;
});
break;
default:
throw new AssertionError("Unsupported platform: " +
OperatingSystem.current());
}
}
OperatingSystem.current()
方法,获取到当前系统类型的枚举值,OperatingSystem为枚举类型。在我看的OpenJDK 21 代码中,支持四种系统类型Linux、MacOS,Windows,AIX
而OperatingSystem.current()
方法本身的获取系统类型的方法,是从OperatingSystem.initOS()
方法处初始化获得的。
private static OperatingSystem initOS() {
return OperatingSystem.valueOf(PlatformProps.CURRENT_OS_STRING.toUpperCase(Locale.ROOT));
}
其中,PlatformProps.CURRENT_OS_STRING
,下载JDK时就会根据平台下载到不同文件,一开始就是固定的值。
class PlatformProps {
// Name of the current OperatingSystem enum as substituted by the build
static final String CURRENT_OS_STRING = "macos";
......
}