Java——进程

来源:互联网 发布:pg报丧女妖网络限定 编辑:程序博客网 时间:2024/06/08 11:52

进程

进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位, 每个进程都有其自己的内存空间。Java中创建进程其实是创建了操作系统的一个进程,Java虚拟机本身就是一个进程,该进程创建了多个线程能够同时运行的条件。

进程特征

动态性:进程的实质是程序在多道程序系统中的一次执行过程,进程是动态产生,动态消亡的;

并发性:任何进程都可以同其他进程一起并发执行;

独立性:进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位;

异步性:由于进程间的相互制约,使进程具有执行的间断性,即进程按各自独立的、不可预知的速度向前推进。

结构特征:进程由程序、数据和进程控制块三部分组成。

进程间通信

大多数操作系统都支持进程间通信( Inter Process Communication,简称 IPC)资源,如管道,共享内存和套接字等。(这块还不是很清楚)

Java进程的创建

Java提供了两种方法用来创建进程。

使用Runtime的exec()方法

源码中exec()方法最后是调用了ProcessBuilder的start()方法创建进程,源码如下。

public Process exec(String[] cmdarray, String[] envp, File dir)        throws IOException {        return new ProcessBuilder(cmdarray)            .environment(envp)            .directory(dir)            .start();    }

我用的是mac,看到的调用链是

Runtime的exec()——》new ProcessBuilder调用start()方法——》ProcessImpl.start()——》new UNIXProcess

UNIXProcess继承自抽象类Process,是实现了Process中方法的final类,该类中有处理进程的一些native方法。

Java.lang.Runtime.exec 方法和 Java.lang.ProcessBuilder.start 方法都可以创建一个本地的进程,然后返回代表这个进程的 Java.lang.Process 引用。

参考jdk1.8的源码

示例代码

在某个目录执行ls命令,列出目录下内容。

public int createProcessByRunTime() throws IOException{        int resultCode = -1;        Process process = Runtime.getRuntime().exec("top", null, new File("/Users/gary/Documents/workspace"));        //获取进程执行后结果        try(InputStream inputStream = process.getInputStream();            ByteArrayOutputStream outputStream = new ByteArrayOutputStream()){            byte[] buf = new byte[1024];            int length;            while((length = inputStream.read(buf)) != -1){                outputStream.write(buf, 0, length);            }            String result = outputStream.toString("utf-8");            System.out.println(result);            //阻塞当前线程直到进程执行结束,执行成功返回0            resultCode = process.waitFor();            //立即返回执行结果,进程没有结束,可能会抛异常 IllegalThreadStateException            //resultCode = process.exitValue();            return resultCode;        } catch(InterruptedException e) {            e.printStackTrace();        }        return resultCode;    }

运行结果:

RemoteSystemsTempFilesServerscommongradlePracticestatistics0

比如把程序的 ls 命令换成 top 命令,然后用 process.exitValue()获取返回值,就会报下面的错误。

Exception in thread "main" java.lang.IllegalThreadStateException: process hasn't exited

使用ProcessBuilder的start()方法

看源码可以发现start方法中是调用了ProcessImpl类的start()方法,可以预先配置 ProcessBuilder 的属性是通过 ProcessBuilder 创建进程的最大优点。

示例代码

 public int createProcessByProcessbuilder() throws IOException{        int resultCode = -1;        ProcessBuilder processBuilder = new ProcessBuilder("ls");        //默认为FALSE,设为true后,标准错误将与标准输出合并,通过getInputStream获取输出信息        processBuilder.redirectErrorStream(true);        Process process = processBuilder.directory(new File("/Users/gary/Documents/workspace")).start();        //获取进程执行后结果        try(InputStream inputStream = process.getInputStream();            ByteArrayOutputStream outputStream = new ByteArrayOutputStream()){            byte[] buf = new byte[1024];            int length;            while((length = inputStream.read(buf)) != -1){                outputStream.write(buf, 0, length);            }            String result = outputStream.toString("utf-8");            System.out.println(result);            //阻塞当前线程直到进程执行结束            resultCode = process.waitFor();            //立即返回执行结果,进程没有结束,可能会抛异常 IllegalThreadStateException            //resultCode = process.exitValue();            return resultCode;        }catch(InterruptedException e) {            e.printStackTrace();        }        return resultCode;    }

获取进程执行后返回码

一个程序/进程在执行结束后会向操作系统返回一个整数值,0一般代表执行成功,非0表示执行出现问题。有两种方式可以用来获取进程的返回值:一是利用waitFor(),该方法是阻塞的,直到进程执行完成后再返回。该方法返回一个代表进程返回值的整数值;另一个方法是调用exitValue()方法,该方法是非阻塞的,调用立即返回。但是如果进程没有执行完成,则抛出异常IllegalThreadStateException

可以使用ProcessBuilder的redirectErrorStream(true)方法将标准错误与标准输出合并,这时候只要读取标准输出的数据就可以了。

参考资料

java创建进程(很详细)
Java 中的进程与线程

0 0
原创粉丝点击