多进程编程

简介: 多进程编程

前言

Java对操作系统提供的多进程编程接口这些操作进行了限制,最终给用户只提供了两个操作:进程创建和进程等待


一、进程创建

创建出一个新的进程,让这个新的进程来执行一系列的任务。被创建出来的进程,称为“子进程”;创建子进程的进程。称为“父进程”(谈到多进程,经常会涉及到“父进程,子进程”,但是对于多线程,就没有这种说法)。咱们的服务器进程就相当于父进程,根据服务器进程再创建出来子进程。一个父进程可能有多个子进程,但是一个子进程,只能有一个父进程。Java中内置了一个类 Runtime,就可以根据Runtime.exec方法创建出一个子进程。其中在使用exec这个方法的时候,会传入一个参数。参数是一个字符串,表示一个可执行程序的路径。执行这个方法,就会把指定路径的可执行程序创建出进程并执行。(以下为javac命令创建子进程为例

        //Runtime 在JVM中是一个单例
        Runtime runtime = Runtime.getRuntime();
        //Process就表示“进程”
        Process process = runtime.exec("javac");


执行Process process = runtime.exec("javac")这个代码,就相当于在cmd中输入了一个对应的指令。


如果出现这种情况,是因为我们的操作系统不认识这个 javac 是什么。其实在输入命令后,操作系统会去一些特定的目录中找,看看是否存在这个对应的可执行文件,存在才能执行,找不到就会出现上面的提示。如果是系统自带的,比如输入“calc(计算器)”马上就会执行计算器这个程序,但是javac本来就是属于外部安装的,不是系统自带的。解决这个问题的方法就是,配置环境变量,即把javac所在的目录加入到path环境变量中。这一点很简单,不做详细介绍了........

javac是一个控制台程序,它的输出是输入到“标准输出”和“标准错误”这两个特殊的文件中的。想要看到这个程序的运行效果,就得获取到标准输出和标准错误的内容。


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

1.标准输入 对应到键盘

2.标准输出  对应到显示器

3.标准错误  对应到显示器


虽然子进程启动后同样也打开了这三个文件,但是由于子进程没有和IDEA的终端关联,因此在IDEA中是看不到子进程的输出的。要想获取到输出,就需要在代码中手动获取到,可以通过上面的 process 获取到。

   public static void main(String[] args) throws IOException {
        //Runtime 在JVM中是一个单例
        Runtime runtime = Runtime.getRuntime();
        //Process就表示“进程”
        Process process = runtime.exec("javac");
        //获取到子进程的标准输出和标准错误,把这里的内容写入到两个文件中。
        //获取到标准输出
        InputStream stdoutFrom = process.getInputStream();
        FileOutputStream stdoutTo = new FileOutputStream("stdout.txt");
        while (true){
            int ch = stdoutFrom.read();
            if (ch == -1){
                break;
            }
            stdoutTo.write(ch);
        }
        stdoutFrom.close();
        stdoutTo.close();
        //获取标准错误,从这个文件对象中读取,就能把子进程的标准错误给读出来
        InputStream stderrFrom = process.getErrorStream();
        FileOutputStream stderrTo = new FileOutputStream("stderr.txt");
        while (true){
            int ch = stderrFrom.read();
            if (ch == -1){
                break;
            }
            stderrTo.write(ch);
        }
        stderrTo.close();
        stderrFrom.close();
    }


然后运行,就会出现两个文件,就获取到了javac子进程里面的内容。

二、进程等待

Process process = runtime.exec("javac");

通过这个代码,确实能够创建出子进程,但是此时父子进程之间是“并发执行”的关系。另一方面,往往也需要让父进程知道子进程的执行状态。

在某些场景中,希望父进程等待子进程执行完毕之后,再执行后序代码。比如像在线OJ系统,需要让用户提交代码 ,编译执行代码。肯定是要在编译执行完毕之后,再把响应返回给用户。那么此时父进程就需要等待。

//通过Process类的 waitFor 方法来实现进程的等待。
        //当父进程执行到waitFor的时候,就会阻塞,一直阻塞到子进程执行完毕为止。
        //与多线程中的join是非常类似的
        //这个退出码就表示子进程的执行结果是否ok,如果子进程的代码执行完了就正常退出,此时的退出码就是0;
        //如果子进程在执行过程中出现异常(抛异常),那么返回的退出码就是非0;
        int exitCode = process.waitFor();

注意:当前的代码是裸运行javac(正常的javac后面会跟上具体的.java文件名字之类的),退出码是非0的。


相关文章
|
4月前
|
消息中间件 存储 缓存
【嵌入式软件工程师面经】Linux系统编程(线程进程)
【嵌入式软件工程师面经】Linux系统编程(线程进程)
101 1
|
3月前
|
安全 Python
告别低效编程!Python线程与进程并发技术详解,让你的代码飞起来!
【7月更文挑战第9天】Python并发编程提升效率:**理解并发与并行,线程借助`threading`模块处理IO密集型任务,受限于GIL;进程用`multiprocessing`实现并行,绕过GIL限制。示例展示线程和进程创建及同步。选择合适模型,注意线程安全,利用多核,优化性能,实现高效并发编程。
58 3
|
1月前
|
存储 算法 Linux
C语言 多进程编程(一)进程创建
本文详细介绍了Linux系统中的进程管理。首先,文章解释了进程的概念及其特点,强调了进程作为操作系统中独立可调度实体的重要性。文章还深入讲解了Linux下的进程管理,包括如何获取进程ID、进程地址空间、虚拟地址与物理地址的区别,以及进程状态管理和优先级设置等内容。此外,还介绍了常用进程管理命令如`ps`、`top`、`pstree`和`kill`的使用方法。最后,文章讨论了进程的创建、退出和等待机制,并展示了如何通过`fork()`、`exec`家族函数以及`wait()`和`waitpid()`函数来管理和控制进程。此外,还介绍了守护进程的创建方法。
C语言 多进程编程(一)进程创建
|
27天前
|
安全 开发者 Python
揭秘Python IPC:进程间的秘密对话,让你的系统编程更上一层楼
【9月更文挑战第8天】在系统编程中,进程间通信(IPC)是实现多进程协作的关键技术。IPC机制如管道、队列、共享内存和套接字,使进程能在独立内存空间中共享信息,提升系统并发性和灵活性。Python提供了丰富的IPC工具,如`multiprocessing.Pipe()`和`multiprocessing.Queue()`,简化了进程间通信的实现。本文将从理论到实践,详细介绍各种IPC机制的特点和应用场景,帮助开发者构建高效、可靠的多进程应用。掌握Python IPC,让系统编程更加得心应手。
23 4
|
1月前
|
Linux C语言
C语言 多进程编程(三)信号处理方式和自定义处理函数
本文详细介绍了Linux系统中进程间通信的关键机制——信号。首先解释了信号作为一种异步通知机制的特点及其主要来源,接着列举了常见的信号类型及其定义。文章进一步探讨了信号的处理流程和Linux中处理信号的方式,包括忽略信号、捕捉信号以及执行默认操作。此外,通过具体示例演示了如何创建子进程并通过信号进行控制。最后,讲解了如何通过`signal`函数自定义信号处理函数,并提供了完整的示例代码,展示了父子进程之间通过信号进行通信的过程。
|
1月前
|
Linux C语言
C语言 多进程编程(四)定时器信号和子进程退出信号
本文详细介绍了Linux系统中的定时器信号及其相关函数。首先,文章解释了`SIGALRM`信号的作用及应用场景,包括计时器、超时重试和定时任务等。接着介绍了`alarm()`函数,展示了如何设置定时器以及其局限性。随后探讨了`setitimer()`函数,比较了它与`alarm()`的不同之处,包括定时器类型、精度和支持的定时器数量等方面。最后,文章讲解了子进程退出时如何利用`SIGCHLD`信号,提供了示例代码展示如何处理子进程退出信号,避免僵尸进程问题。
|
1月前
|
消息中间件 Unix Linux
C语言 多进程编程(五)消息队列
本文介绍了Linux系统中多进程通信之消息队列的使用方法。首先通过`ftok()`函数生成消息队列的唯一ID,然后使用`msgget()`创建消息队列,并通过`msgctl()`进行操作,如删除队列。接着,通过`msgsnd()`函数发送消息到消息队列,使用`msgrcv()`函数从队列中接收消息。文章提供了详细的函数原型、参数说明及示例代码,帮助读者理解和应用消息队列进行进程间通信。
|
1月前
|
缓存 Linux C语言
C语言 多进程编程(六)共享内存
本文介绍了Linux系统下的多进程通信机制——共享内存的使用方法。首先详细讲解了如何通过`shmget()`函数创建共享内存,并提供了示例代码。接着介绍了如何利用`shmctl()`函数删除共享内存。随后,文章解释了共享内存映射的概念及其实现方法,包括使用`shmat()`函数进行映射以及使用`shmdt()`函数解除映射,并给出了相应的示例代码。最后,展示了如何在共享内存中读写数据的具体操作流程。
|
1月前
|
消息中间件 Unix Linux
C语言 多进程编程(二)管道
本文详细介绍了Linux下的进程间通信(IPC),重点讨论了管道通信机制。首先,文章概述了进程间通信的基本概念及重要性,并列举了几种常见的IPC方式。接着深入探讨了管道通信,包括无名管道(匿名管道)和有名管道(命名管道)。无名管道主要用于父子进程间的单向通信,有名管道则可用于任意进程间的通信。文中提供了丰富的示例代码,展示了如何使用`pipe()`和`mkfifo()`函数创建管道,并通过实例演示了如何利用管道进行进程间的消息传递。此外,还分析了管道的特点、优缺点以及如何通过`errno`判断管道是否存在,帮助读者更好地理解和应用管道通信技术。
|
1月前
|
Linux C语言
C语言 多进程编程(七)信号量
本文档详细介绍了进程间通信中的信号量机制。首先解释了资源竞争、临界资源和临界区的概念,并重点阐述了信号量如何解决这些问题。信号量作为一种协调共享资源访问的机制,包括互斥和同步两方面。文档还详细描述了无名信号量的初始化、等待、释放及销毁等操作,并提供了相应的 C 语言示例代码。此外,还介绍了如何创建信号量集合、初始化信号量以及信号量的操作方法。最后,通过实际示例展示了信号量在进程互斥和同步中的应用,包括如何使用信号量避免资源竞争,并实现了父子进程间的同步输出。附带的 `sem.h` 和 `sem.c` 文件提供了信号量操作的具体实现。

相关实验场景

更多
下一篇
无影云桌面