Java - 多进程编程(对比线程、API 操作)

news/2025/2/22 7:03:40/

目录

一、多进程编程

1.1、为什么要使用多进程编程

1.2、Java 中多进程编程的实现

1.2.1、前言

1.2.2、进程创建

1.2.3、进程等待

1.2.4、封装操作到一个工具类中


一、多进程编程


1.1、为什么要使用多进程编程

一个 .exe 文件执行以后,就会变成一个进程. 

多进程的由来:为了解决某些大型复杂问题,就需要把一个很大的任务,拆分成一个小的任务,进一步的,就需要使用 “多进程编程”,也就是床技安多个进程,每个进程分别负责其中一部分任务.  与此同时,也带来一个问题——“进程的 创建/销毁,比较重量(低效)”.

线程的由来:引入了线程,相比于 进程的 创建/销毁 更加高效,因此 Java 圈子中,大部分并发编程都是通过多线程的方式来实现.

什么情况下要使用多进程编程呢?

进程相比于线程最大的优势就是:进程的 “独立性”.

  • 多线程劣势:一个操作系统上,同一时刻一个进程中运行着多个线程(共用一个地址空间),某个线程挂了,就可能把整个线程带走;
  • 多进程优势:一个操作系统上,同一时刻运行着很多进程,由于不同的进程有各自的地址空间,那么即使某一个进程挂了,也不会影响到其他进程.

比如在一个 OJ 系统中,用户提交的代码就是一个独立的逻辑,整个逻辑就需要使用多进程的方式来执行.  因为用户的代码很有可能是存在问题的(一运行就崩溃),使用多线程就很有可能导致用户代码直接把整个服务器进程搞挂.

1.2、Java 中多进程编程的实现

1.2.1、前言

在操作系统的角度上(例如 Linux),提供了很多和多线程编程相关的接口,例如 进程创建、进程终止、进程等待、进程程序替换、进程间通讯.

但是在 Java 中对这些操作进行了限制,最终只提供了两个操作:进程创建 和 进程等待.

1.2.2、进程创建

通过 Runtime 实例中的 exec 方法(参数是一个字符串,相当于在 cmd 中输入了一个对应的指令)就可以创建出一个进程, 被创建出来的进程称为 “子进程”,创建子进程的进程称为 “父进程”.  咱们的服务器进程就相当于父进程,它可以有多个子进程,但是一个子进程只能有一个父进程.

一个进程在启动的时候,就会自动以下打开三个文件:

  1. 标准输入:对应到键盘.
  2. 标准输出:对应到显示器,用来正确的输出.
  3. 标准错误:对应到显示器,用来展示错误输出.

Ps:在 IDEA 中式看不到子进程的输出的,想要获取,可以手动获取.

例如,创建一个子进程运行 javac 命令,通过输入输出流,将子进程的 标准输出 和 错误输出 写到对应文件中. 

    public static void main(String[] args) throws IOException, InterruptedException {//Runtime 再 JVM 中是一个单例Runtime runtime = Runtime.getRuntime();//Process 就表示进程Process process = runtime.exec("javac");//获取子进程的标准输出和标准错误,并写道两个文件中//1.标准hou出//1) 通过 标准输入流 将子进程的标准输出读出来,写入到 stdout.txt 文件中InputStream stdoutFrom = process.getInputStream();FileOutputStream stdoutTo = new FileOutputStream("stdout.txt");while(true) {int ch = stdoutFrom.read();if(ch == -1) { //读到 EOF 为止(EOF 就是 -1)break;}stdoutTo.write(ch);}//2) 释放文件描述符stdoutFrom.close();stdoutTo.close();//2.标准错误//2) 通过标准输入流 将子进程的标准错误读出来,写入到 stderr.txtInputStream stderrFrom = process.getErrorStream();FileOutputStream stderrTo = new FileOutputStream("stderr.txt");while(true) {int ch = stderrFrom.read();if(ch == -1) {break;}stderrTo.write(ch);}//2) 释放文件描述符stderrFrom.close();stderrTo.close();}

运行后可以看到生成如下两个文件:

由于这里我只是单纯的输入 javac 命令(没有指定编译的 jar 包),因此是一个错误命令,那么就可以在 标准错误 中看到如下信息:

Ps:javac 往控制台输出的命令,再 windows 简体中文版系统中,默认是 gbk 编码,idea 默认式 utf8,打开后可能会乱码,因此只需要再 idea 提示中,通过 gbk 重新加载即可.

在 cmd 中输入 javac 也是一样的结果:

1.2.3、进程等待

在某些场景中,我们希望父进程等待子进程执行完毕以后,再执行后续的代码. 

例如,OJ 系统就需要让用户提交代码,然后编译执行代码,再把执行结果的响应返回给用户.

具体实现如下:

通过 Process 类中的 waitFor 方法实现进程等待,父进程执行到 waitFor 的时候就会阻塞,知道子进程执行完毕为止(类似 Thread.join). 最后会返回一个退出码,表示子进程执行结果是否 ok,正常退出就返回 0,异常退出(子进程执行过程中抛异常了)就非0.

        //进程等待int exitCode = process.waitFor();System.out.println(exitCode);

1.2.4、封装操作到一个工具类中

通常,我们会将进程创建和等待封装到一个工具类中去使用.

public class CommandUtil {/*** @param cmd 进程要执行的命令* @param stdout 标准输出文件名 + 后缀* @param stderr 标准错误文件名 + 后缀* @return 进程等待后返回的状态码*/public static int run(String cmd, String stdout, String stderr) {try {//1.获取 Runtime 实例,执行 exec 方法Runtime runtime = Runtime.getRuntime();Process process = runtime.exec(cmd);//2.获取 标准输出if(stdout != null) {InputStream stdoutFrom = process.getInputStream();FileOutputStream stdoutTo = new FileOutputStream(stdout);while(true) {int read = stdoutFrom.read();if(read == -1) {break;}stdoutTo.write(read);}stdoutFrom.close();stdoutTo.close();}//3.获取 标准错误if(stderr != null) {InputStream stderrFrom = process.getErrorStream();FileOutputStream stderrTo = new FileOutputStream(stderr);while(true) {int read = stderrFrom.read();if(read == -1) {break;}stderrTo.write(read);}stderrFrom.close();stderrTo.close();}//4.进程等待return process.waitFor();} catch (Exception e) {e.printStackTrace();}//返回异常的状态码return 1;}//测试public static void main(String[] args) {int result = run("javac", "stdout.txt", "stderr.txt");System.out.println(result);}}


http://www.ppmy.cn/news/1167741.html

相关文章

Ubuntu22.04安装nvidia-docker

安装docker 参考这篇文章:Ubuntu22.04安装docker - 掘金 安装nvidia-docker 参考这篇文章:Ubuntu 22.04 LTS : NVIDIA Container Toolkit : Install : Server World 流程: curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | …

统计学习方法 感知机

文章目录 统计学习方法 感知机模型定义学习策略学习算法原始算法对偶算法 学习算法的收敛性 统计学习方法 感知机 读李航的《统计学习方法》时,关于感知机的笔记。 感知机(perceptron)是一种二元分类的线性分类模型,属于判别模型…

创新的营销模式与线上商城的完美结合

分享购,一个与众不同的电商平台,以一种全新的营销模式和独特的商业运营模式,颠覆了传统电商的观念,让每个人都能拥有属于自己的线上商城。它集自营品牌、供应链管理和CPS等多种优势于一身,形成了一种创新的交易和共享生…

探讨Socks5代理技术的原理及其在不同领域的应用

Socks5代理:实现网络连接的智能之选 作为一种网络代理协议,Socks5代理技术通过转发网络数据包,实现了客户端和服务器之间的代理传输。其独特的特性在跨界电商、爬虫数据分析、企业出海和游戏体验等领域发挥着关键作用,为用户提供…

正则表达式之学习笔记

正则表达式学习笔记 一、概念二、正则表达式组成三、常见的正则表达式3.1 .匹配任意字符3.2 * 匹配前一个字符的0个或多个实例3.3 ^ 匹配输入字符串的开头3.4 $ 匹配行尾3.5 [] 匹配字符集合\<\> 精确匹配符号 一、概念 正则表达式是由一系列特殊字符组成的字符串&#…

Pyside6 QFileDialog

Pyside6 QFileDialog Pyside6 QFileDialog常用函数getOpenFileNamegetOpenFileNamesgetExistingDirectorygetSaveFileName 程序界面程序主程序 Pyside6 QFileDialog提供了一个允许用户选择文件或目录的对话框。关于QFileDialog的使用可以参考下面的文档 https://doc.qt.io/qtfo…

2016-2023全国MBA国家A类线趋势图:浙大MBA要高多少?

距离2024年MBA联考还有两个月左右的时间&#xff0c;冲刺阶段需要为目标做最后的努力。关于分数的目标&#xff0c;目前国外的大多数MBA项目的录取门槛都是国家A类线&#xff0c;而后续常规批复试后的调剂门槛多数也是国家A类线&#xff0c;所以国家线应该是多数考生的第一目标…

(矩阵) 289. 生命游戏 ——【Leetcode每日一题】

❓ 289. 生命游戏 难度&#xff1a;中等 根据 百度百科 &#xff0c; 生命游戏 &#xff0c;简称为 生命 &#xff0c;是英国数学家约翰何顿康威在 1970 年发明的细胞自动机。 给定一个包含 m n 个格子的面板&#xff0c;每一个格子都可以看成是一个细胞。每个细胞都具有一…