学习 JDK Process操作子进程的API;包含ProcessBuilder、Process、ProcessHandler核心类API的使用演示以及在不同场景下的案例;

yangyi 403a2548e5 docs: 新增 README,补充 pom 工程描述 1 долоо хоног өмнө
src 9c881baf86 chore: 将中文术语'夹具'替换为'子进程程序',doc.md 补 fixture 溯源注释 1 долоо хоног өмнө
.gitignore 9dc48b3686 chores: ignore compiled fixture classes, remove stray Main.java 1 долоо хоног өмнө
AGENTS.md b60409596d doc: 补充概念铺垫/预期输出/进阶标注/无shell警告/综合运用章节;AGENTS 更新测试说明 1 долоо хоног өмнө
README.md 403a2548e5 docs: 新增 README,补充 pom 工程描述 1 долоо хоног өмнө
blog.md 36191014b6 add blog.md 原文与 template.md 模板参考 1 долоо хоног өмнө
blog2.md 44935fa047 blog: 补充 ProcessHandle 章节(模板风格,接综合实战与附录之间) 1 долоо хоног өмнө
doc.md 9c881baf86 chore: 将中文术语'夹具'替换为'子进程程序',doc.md 补 fixture 溯源注释 1 долоо хоног өмнө
pom.xml 403a2548e5 docs: 新增 README,补充 pom 工程描述 1 долоо хоног өмнө
process.md a2933a72d2 doc: 补充 ProcessHandle 章节(process.md 大纲 + doc.md 详细教程,含 API 表/预期输出/踩坑) 1 долоо хоног өмнө
template.md 36191014b6 add blog.md 原文与 template.md 模板参考 1 долоо хоног өмнө

README.md

process-demo

Maven 单模块示例工程(目标 Java 17),用于学习 ProcessBuilder / Process / ProcessHandle:如何构建一个子进程、读写它的标准输入输出、重定向流、异步处理 I/O、获取执行状态码,以及组合成管道式调用和进程树管理。

所有说明文档与代码注释均为中文,配套教程见 process.md(大纲)、doc.md(完整教程)与 blog.md / blog2.md(博客文章)。

技术栈

  • Java 17(maven.compiler.source/target = 17,UTF-8 编码)
  • 运行时依赖:logback-classic(提供 SLF4J 日志)
  • 测试依赖:junit-jupiter(JUnit 5,由 maven-surefire-plugin 驱动)
  • 无 lint、无 exec-maven-plugin

目录结构

src/main/java/space/anyi/process/   示例代码(public static void main 入口)
  Jdk.java                          共享工具:javac/java 绝对路径、编译 fixture
  QuickStart.java                   示例一:构建并运行子进程
  ProcessIOExample.java            示例二:标准输入/输出/错误流
  ProcessRedirectExample.java       重定向:合并流、文件重定向、Redirect 枚举
  ProcessAsyncExample.java          异步:线程 / CompletableFuture / onExit
  ExecuteStatusExample.java         示例三:waitFor 阻塞与超时销毁
  ProcessBuilderExample.java        环境变量(environment())
  ProcessPipelineExample.java       示例五:管道式组合调用
  ProcessHandleExample.java         示例六:ProcessHandle 进程管理
src/main/resources/code/            子进程程序(fixtures),各目录含 Main.java
  hello/          打印问候语与 PID
  io/             回显 stdin、统计并写入 stderr
  executeStatus/  睡眠 10 秒后退出
  processHandle/  打印 PID/参数,睡眠 30 秒等待父进程观察
src/test/java/space/anyi/process/   ProcessMechanicsTest(端到端测试)
doc.md / process.md / blog.md / blog2.md   教程与博客文档

运行示例

工程没有运行目标,编译后手动运行。需要把依赖 jar 一起放到 classpath(示例使用 slf4j 日志),否则出现 NoClassDefFoundError: org/slf4j/LoggerFactory

mvn -q compile
java -cp "target/classes:$(mvn -q dependency:build-classpath -Dmdep.outputFile=/dev/stdout | tail -1)" space.anyi.process.<ClassName>

例如:

java -cp "target/classes:$(mvn -q dependency:build-classpath -Dmdep.outputFile=/dev/stdout | tail -1)" space.anyi.process.QuickStart

注意:示例的 workDir 相对于 user.dir必须从仓库根目录运行,否则 ProcessBuilder.start()IOException: error=2

测试

mvn test

ProcessMechanicsTest 端到端驱动同一批 child fixtures(会先重新编译 io/executeStatus/),并刻意覆盖「流排水 + 超时/destroy」的常见陷阱。同样要求从仓库根目录运行。

教程要点(出自 doc.md 的踩坑总结)

  1. new BufferedReader(...).lines().forEach(...)阻塞当前线程直到子进程退出;做限时 waitFor(timeout) 时必须在后台线程排水。
  2. Process.waitFor(timeout, unit) 返回的是 boolean 而非退出码;超时返回 false 时子进程仍存活,此时调用 exitValue() 会抛 IllegalThreadStateException,须先 destroy() 再阻塞 waitFor()
  3. 生成的子进程 PATH 往往缺少 JDK bin 目录(error=2),请统一走 Jdk.javac() / Jdk.java() 的绝对路径,不要裸用 javac / java

约定

  • 每个案例点由一个独立的 static 方法演示,统一由 main() 调用。
  • 所有子进程程序均来自 src/main/resources/code/,不使用临时脚本或系统命令。
  • 代码注释为中文,说明每步的作用与原因。