Java中如何创建进程(转)

在Java中,可以通过两种方式来创建进程,总共涉及到5个主要的类。

  第一种方式是通过Runtime.exec()方法来创建一个进程,第二种方法是通过ProcessBuilder的start方法来创建进程。下面就来讲一讲这2种方式的区别和联系。

  首先要讲的是Process类,Process类是一个抽象类,在它里面主要有几个抽象的方法,这个可以通过查看Process类的源代码得知:

  位于java.lang.Process路径下:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

public abstract class Process

{

   

    abstract public OutputStream getOutputStream();   //获取进程的输出流

     

    abstract public InputStream getInputStream();    //获取进程的输入流

    abstract public InputStream getErrorStream();   //获取进程的错误流

    abstract public int waitFor() throws InterruptedException;   //让进程等待

 

    abstract public int exitValue();   //获取进程的退出标志

    abstract public void destroy();   //摧毁进程

}

  1)通过ProcessBuilder创建进程

  ProcessBuilder是一个final类,它有两个构造器:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

public final class ProcessBuilder

{

    private List<String> command;

    private File directory;

    private Map<String,String> environment;

    private boolean redirectErrorStream;

    public ProcessBuilder(List<String> command) {

    if (command == null)

        throw new NullPointerException();

    this.command = command;

    }

    public ProcessBuilder(String... command) {

    this.command = new ArrayList<String>(command.length);

    for (String arg : command)

        this.command.add(arg);

    }

....

}

  构造器中传递的是需要创建的进程的命令参数,第一个构造器是将命令参数放进List当中传进去,第二构造器是以不定长字符串的形式传进去。

  那么我们接着往下看,前面提到是通过ProcessBuilder的start方法来创建一个新进程的,我们看一下start方法中具体做了哪些事情。下面是start方法的具体实现源代码:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

public Process start() throws IOException {

// Must convert to array first -- a malicious user-supplied

// list might try to circumvent the security check.

String[] cmdarray = command.toArray(new String[command.size()]);

for (String arg : cmdarray)

    if (arg == null)

    throw new NullPointerException();

// Throws IndexOutOfBoundsException if command is empty

String prog = cmdarray[0];

SecurityManager security = System.getSecurityManager();

if (security != null)

    security.checkExec(prog);

String dir = directory == null ? null : directory.toString();

try {

    return ProcessImpl.start(cmdarray,

                 environment,

                 dir,

                 redirectErrorStream);

} catch (IOException e) {

    // It‘s much easier for us to create a high-quality error

    // message than the low-level C code which found the problem.

    throw new IOException(

    "Cannot run program \"" + prog + "\""

    + (dir == null ? "" : " (in directory \"" + dir + "\")")

    + ": " + e.getMessage(),

    e);

}

}

  该方法返回一个Process对象,该方法的前面部分相当于是根据命令参数以及设置的工作目录进行一些参数设定,最重要的是try语句块里面的一句:


1

2

3

4

return ProcessImpl.start(cmdarray,

                    environment,

                    dir,

                    redirectErrorStream);

  说明真正创建进程的是这一句,注意调用的是ProcessImpl类的start方法,此处可以知道start必然是一个静态方法。那么ProcessImpl又是什么类呢?该类同样位于java.lang.ProcessImpl路径下,看一下该类的具体实现:

  ProcessImpl也是一个final类,它继承了Process类:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

final class ProcessImpl extends Process {

    // System-dependent portion of ProcessBuilder.start()

    static Process start(String cmdarray[],

             java.util.Map<String,String> environment,

             String dir,

             boolean redirectErrorStream)

    throws IOException

    {

    String envblock = ProcessEnvironment.toEnvironmentBlock(environment);

    return new ProcessImpl(cmdarray, envblock, dir, redirectErrorStream);

    }

 ....

}

  这是ProcessImpl类的start方法的具体实现,而事实上start方法中是通过这句来创建一个ProcessImpl对象的:


1

return new ProcessImpl(cmdarray, envblock, dir, redirectErrorStream);

  而在ProcessImpl中对Process类中的几个抽象方法进行了具体实现。

  说明事实上通过ProcessBuilder的start方法创建的是一个ProcessImpl对象。

  下面看一下具体使用ProcessBuilder创建进程的例子,比如我要通过ProcessBuilder来启动一个进程打开cmd,并获取ip地址信息,那么可以这么写:


1

2

3

4

5

6

7

8

9

10

11

12

public class Test {

    public static void main(String[] args) throws IOException  {

        ProcessBuilder pb = new ProcessBuilder("cmd","/c","ipconfig/all");

        Process process = pb.start();

        Scanner scanner = new Scanner(process.getInputStream());

        

        while(scanner.hasNextLine()){

            System.out.println(scanner.nextLine());

        }

        scanner.close();

    }

}

  第一步是最关键的,就是将命令字符串传给ProcessBuilder的构造器,一般来说,是把字符串中的每个独立的命令作为一个单独的参数,不过也可以按照顺序放入List中传进去。

  至于其他很多具体的用法不在此进行赘述,比如通过ProcessBuilder的environment方法和directory(File directory)设置进程的环境变量以及工作目录等,感兴趣的朋友可以查看相关API文档。

  2)通过Runtime的exec方法来创建进程

  首先还是来看一下Runtime类和exec方法的具体实现,Runtime,顾名思义,即运行时,表示当前进程所在的虚拟机实例。

  由于任何进程只会运行于一个虚拟机实例当中,所以在Runtime中采用了单例模式,即只会产生一个虚拟机实例:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

public class Runtime {

    private static Runtime currentRuntime = new Runtime();

    /**

     * Returns the runtime object associated with the current Java application.

     * Most of the methods of class <code>Runtime</code> are instance

     * methods and must be invoked with respect to the current runtime object.

     *

     * @return  the <code>Runtime</code> object associated with the current

     *          Java application.

     */

    public static Runtime getRuntime() {

    return currentRuntime;

    }

    /** Don‘t let anyone else instantiate this class */

    private Runtime() {}

    ...

 }

  从这里可以看出,由于Runtime类的构造器是private的,所以只有通过getRuntime去获取Runtime的实例。接下来着重看一下exec方法 实现,在Runtime中有多个exec的不同重载实现,但真正最后执行的是这个版本的exec方法:


1

2

3

4

5

6

7

public Process exec(String[] cmdarray, String[] envp, File dir)

   throws IOException {

   return new ProcessBuilder(cmdarray)

       .environment(envp)

       .directory(dir)

       .start();

   }

  可以发现,事实上通过Runtime类的exec创建进程的话,最终还是通过ProcessBuilder类的start方法来创建的。

  下面看一个例子,看一下通过Runtime的exec如何创建进程,还是前面的例子,调用cmd,获取ip地址信息:


1

2

3

4

5

6

7

8

9

10

11

12

public class Test {

    public static void main(String[] args) throws IOException  {

        String cmd = "cmd "+"/c "+"ipconfig/all";

        Process process = Runtime.getRuntime().exec(cmd);

        Scanner scanner = new Scanner(process.getInputStream());

        

        while(scanner.hasNextLine()){

            System.out.println(scanner.nextLine());

        }

        scanner.close();

    }

}

  要注意的是,exec方法不支持不定长参数(ProcessBuilder是支持不定长参数的),所以必须先把命令参数拼接好再传进去。

  关于在Java中如何创建线程和进程的话,暂时就讲这么多了,感兴趣的朋友可以参考相关资料

http://www.cnblogs.com/dolphin0520/p/3913517.html

Java中如何创建进程(转),布布扣,bubuko.com

时间: 2024-10-03 21:41:13

Java中如何创建进程(转)的相关文章

在java中如何创建一个内存泄露

今天访问java 并发编程网,看到一个翻译征集令,并发编程网的作者从stackoverflow 网站上选取了一些经典问答,遂决定翻译几篇 征集令地址:http://ifeve.com/stackoverflow-assembly/ 翻译系列文章: 1.Java 核心类库中的一些设计模式 2. hashMap 与hashTable之间的区别 3.  在java中如何创建一个内存泄露 译文: 在java中如何创建一个内存泄露 问题: 我之前参加了一个面试, 被问到在java中如何创建一个内存泄露.不

java中如何创建带路径的文件

请教各位大侠了,java中如何创建带路径的文件,说明下 这个路径不存在 ------回答--------- ------其他回答(2分)--------- Java code File f = new File("c:/1.txt"); if(!f.exists()){ try { f.createNewFile(); } catch (IOException e) { e.printStackTrace(); } } ------其他回答(18分)--------- Java cod

java中的并发:进程和线程

1.简介 1)进程:同一个系统中执行的一个子程序,包含三部分:虚拟CPU,代码,数据. 2)线程:同一个进程中执行的子程序流. 3)进程让操作系统的并发性成为可能,而线程让进程的内部并发成为可能.一个进程虽然包括多个线程,但是这些线程是共同享有进程占有的资源和地址空间的.进程是操作系统进行资源分配的基本单位,而线程是操作系统进行调度的基本单位. 2.创建一个进程 2.1首先了解三个类    1)Process(抽象类)       进程类,提供了执行从进程输入.执行输出到进程.等待进程完成.检查

Java中String创建原理深入分析

1.  使用new关键字 String s1 = new String("ab");  // 2.  使用字符串常量直接赋值 String s2 = "abc"; 3.  使用"+"运算符进行字符串连接 String s3 = "abc" + "d"; String s4 = s3 + 5;  //abcd5 常量池概念: Java运行时会维护一个String Pool(String池), 也叫"

《Java中对象创建过程》

http://jzinfo.iteye.com/blog/620045具体问题:java中使用new创建一个对象的时候,详细的过程是怎么样的. Java中每个Java代码要能执行首先会编译成一个class的字节码文件.然后利用类装载器装载进入JVM然后才能被执行. 1. 所有的类都是在对其第一次使用时,动态加载到JVM中.当首次创建类型为Dog的对象时,或者Dog类的静态方法,静态属性域首次被访问时,java解释器查找classPath,定位到Dog.class文件 2. 载入Dog.class

【Simple Java】Java中怎样创建线程安全的方法

面试问题: 下面的方法是否线程安全?怎样让它成为线程安全的方法? class MyCounter { private static int counter = 0; public static int getCount() { return counter++; } } 本篇文章将解释一个常见的面试题,该问题被谷歌和很多其它公司问起过.它涉及的相对比较初级,而不是关于怎样去设计复杂的并发程序. 首先,这个问题的答案是No,因为counter++操作不是一个原子操作,而是由多个原子操作组成. 举个

JAVA中对象创建和初始化过程

1.Java中的数据类型 Java中有3个数据类型:基本数据类型(在Java中,boolean.byte.short.int.long.char.float.double这八种是基本数据类型).引用类型和null类型.其中,引用类型包括类类型(含数组).接口类型. 下列语句声明了一些变量: 以下是引用片段: int k ;  A a; //a是A数据类型的对象变量名.  B b1,b2,-,b10000;// 假定B是抽象类或接口.  String s; 注意:从数据类型与变量的角度看,基本数据

Java中程序、进程、线程的区别。

程序.进程.线程的区别. 程序(program):是一个指令的集合.程序不能独立执行,只有被加载到内存中,系统为他分配资源后才能执行. 进程(process):一个执行中的程序称为进程. 进程是系统分配资源的独立单位,每个进程战友特定的地址空间. 程序是进程的静态文本描述.进程是程序在系统内顺序执行的动态活动. 线程(thread):是进程的"单一的连续控制流程". 线程是CPU调度和分配的基本单位,是比进程更小的能独立运行的基本单位,也被称为轻量级的进程. 线程不能独立存在,必须依附

【原创】java中的父进程子进程 —— 坑爹的java Runtime.getRuntime().exec

最近有一个需求,需要用一个java进程启动多个子进程来完成并发任务.由于必须给用户完成任务的反馈,所以需要父进程记录子进程的生命周期. exec方法返回一个Process对象,在当前进程内调用该对象的waitFor方法,然后父进程就会在该方法阻塞,那么只有在该Process结束的情况下,才会从waitFor中返回. 我写了两个类来测试: 一个是Father类: public class Father { private static int count = 0; private static i