Skip to content

进程间通信方式


管道(Pipe)

一、是什么?
管道是半双工的单向通信通道,数据只能单向流动(一个进程写,另一个进程读)。分为:

  • 匿名管道:仅用于父子进程或有亲缘关系的进程
  • 命名管道(FIFO):无亲缘关系的进程可通过文件系统路径访问

二、解决什么问题
解决有亲缘关系进程间的简单数据传递问题,如命令行中的 | 操作符(ls | grep txt)。

三、应用场景

  1. Shell命令链中进程的数据传递
  2. 父子进程间的简单通信
  3. 日志收集系统(生产者-消费者模型)

四、Java示例

java
// 使用ProcessBuilder创建管道
ProcessBuilder processBuilder1 = new ProcessBuilder("echo", "Hello Pipe");
ProcessBuilder processBuilder2 = new ProcessBuilder("grep", "Hello");

// 连接两个进程
processBuilder1.redirectOutput(ProcessBuilder.Redirect.PIPE);
processBuilder2.redirectInput(processBuilder1.redirectOutput());

Process p1 = processBuilder1.start();
Process p2 = processBuilder2.start();

// 读取结果
BufferedReader reader = new BufferedReader(new InputStreamReader(p2.getInputStream()));
System.out.println(reader.readLine());  // 输出:Hello Pipe

五、重要注意事项

  1. 匿名管道只能用于亲缘进程
  2. 数据是字节流,无消息边界
  3. 缓冲区有限(通常4KB),写满时写操作阻塞

消息队列(Message Queue)

一、是什么?
内核维护的消息链表,进程通过唯一标识符访问队列,支持结构化消息传递。

二、解决什么问题
解决无亲缘关系进程间的异步通信需求,支持消息优先级和类型过滤。

三、应用场景

  1. 订单处理系统(生产者-消费者解耦)
  2. 微服务间通信
  3. 跨进程事件通知(如系统监控告警)

四、Java实现方式
Java标准库不直接支持系统级消息队列,但可通过中间件实现:

java
// 使用RabbitMQ示例(需引入amqp-client)
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
try (Connection connection = factory.newConnection();
     Channel channel = connection.createChannel()) {
    channel.queueDeclare("IPC_QUEUE", false, false, false, null);
    // 发送消息
    channel.basicPublish("", "IPC_QUEUE", null, "Hello MQ".getBytes());
}

五、重要注意事项

  1. 消息需要序列化/反序列化
  2. 内核队列有最大长度限制
  3. 持久化消息影响性能

共享内存(Shared Memory)

一、是什么?
多个进程直接访问同一块物理内存区域,是速度最快的IPC方式。

二、解决什么问题
解决大数据量、高性能要求的进程通信场景(如视频处理)。

三、应用场景

  1. 数据库缓冲池管理
  2. 实时图像/视频处理
  3. 高频交易系统

四、Java实现
通过内存映射文件实现:

java
// 进程A:写入共享内存
RandomAccessFile file = new RandomAccessFile("shmem.dat", "rw");
FileChannel channel = file.getChannel();
MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, 1024);
buffer.put("Shared Data".getBytes());

// 进程B:读取相同文件
MappedByteBuffer buffer2 = new RandomAccessFile("shmem.dat", "rw")
    .getChannel()
    .map(FileChannel.MapMode.READ_WRITE, 0, 1024);
byte[] data = new byte[11];
buffer2.get(data);
System.out.println(new String(data));  // 输出:Shared Data

五、重要注意事项

  1. 必须配合信号量等同步机制
  2. 内存一致性需开发者保证
  3. 复杂数据类型需要序列化

Socket

一、是什么?
基于网络协议的通信端点,支持TCP(可靠流)和UDP(数据报)两种模式。

二、解决什么问题
解决跨网络或同主机任意进程间的通用通信问题。

三、应用场景

  1. 分布式系统通信
  2. 微服务架构
  3. 浏览器-服务器交互

四、Java示例

java
// 服务端
try (ServerSocket server = new ServerSocket(8080);
     Socket client = server.accept();
     PrintWriter out = new PrintWriter(client.getOutputStream(), true)) {
    out.println("Hello from Server!");
}

// 客户端
try (Socket socket = new Socket("localhost", 8080);
     BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
    System.out.println(in.readLine());  // 输出:Hello from Server!
}

五、重要注意事项

  1. TCP保证可靠但开销大,UDP高效但不保证可靠
  2. 需要处理网络异常
  3. JDK12+支持Reactive Socket(异步非阻塞)

信号(Signal)

一、是什么?
内核向进程发送的异步事件通知(如SIGINT对应Ctrl+C)。

二、解决什么问题
处理进程异常终止、用户中断等紧急事件。

三、应用场景

  1. 优雅关闭服务(SIGTERM)
  2. 程序调试(SIGTRAP)
  3. 子进程状态变更通知(SIGCHLD)

四、Java处理

java
// 注册关闭钩子(处理SIGTERM)
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
    System.out.println("Cleaning resources before exit");
}));

// 自定义信号处理(Unix-like系统)
sun.misc.Signal.handle(new sun.misc.Signal("USR1"), sig -> {
    System.out.println("Received SIGUSR1");
});

五、重要注意事项

  1. 信号处理函数应保持简单
  2. 某些信号不可捕获(如SIGKILL)
  3. Windows支持有限

信号量(Semaphore)

一、是什么?
用于进程同步的计数器,控制对共享资源的访问权限。

二、解决什么问题
解决多进程竞争共享资源时的互斥与同步问题。

三、应用场景

  1. 数据库连接池管理
  2. 打印机等独占设备调度
  3. 生产者-消费者缓冲区控制

四、Java实现
Java信号量用于线程级同步,进程间需用JNI:

java
// 线程级信号量
Semaphore semaphore = new Semaphore(3); // 允许3个并发访问

void accessResource() {
    semaphore.acquire();
    try { /* 使用共享资源 */ } 
    finally { semaphore.release(); }
}

五、重要注意事项

  1. 需要防止死锁(获取顺序一致)
  2. 信号量不包含数据传递功能
  3. System V信号量支持跨进程

核心区别对比

方式速度亲缘要求数据能力同步需求跨主机
管道匿名管道需要字节流内置同步
消息队列结构化消息可选
共享内存极快任意大数据需要同步
Socket字节流/数据报内置
信号极快仅通知无数据异步
信号量无数据同步控制

总结

  1. 性能优先:选择共享内存(需配合信号量同步)
  2. 简单通信:亲缘进程用管道,非亲缘用消息队列
  3. 网络/分布式:必须使用Socket
  4. 紧急事件:信号处理关键中断
  5. 资源控制:信号量解决并发访问问题

JDK12+新特性

  • java.net包增强支持HTTP/2和WebSocket
  • 响应式编程模型(Reactive Streams)优化Socket通信
  • Foreign-Memory Access API(JEP 370)改进共享内存操作

实际开发中,优先考虑:

  • 单机高性能 → 共享内存+信号量
  • 服务解耦 → 消息队列(如Kafka/RabbitMQ)
  • 通用解决方案 → Socket(HTTP/RESTful API)