![](/icons/14230yi.gif)
般我们在java中运行其它类中
![](/icons/14230de.gif)
思路方法时
![](/icons/14230dou.gif)
无论是静态
![](/icons/14230diaoyong.gif)
![](/icons/14230dou.gif)
还是动态
![](/icons/14230diaoyong.gif)
![](/icons/14230dou.gif)
都是在当前
![](/icons/14230de.gif)
进程中执行
![](/icons/14230de.gif)
![](/icons/14230dou.gif)
也就是说
![](/icons/14230dou.gif)
只有
![](/icons/14230yi.gif)
个java虚拟机例子在运行
![](/icons/14230dou2.gif)
而有
![](/icons/14230de.gif)
时候
![](/icons/14230dou.gif)
我们需要通过java代码启动多个java子进程
![](/icons/14230dou2.gif)
这样做虽然占用了
![](/icons/14230yi.gif)
些系统资源
![](/icons/14230dou.gif)
但会使
![](/icons/14230chengxu.gif)
更加稳定
![](/icons/14230dou.gif)
![](/icons/14230yinwei.gif)
新启动
![](/icons/14230de.gif)
![](/icons/14230chengxu.gif)
是在区别
![](/icons/14230de.gif)
虚拟机进程中运行
![](/icons/14230de.gif)
![](/icons/14230dou.gif)
如果有
![](/icons/14230yi.gif)
个进程发生异常
![](/icons/14230dou.gif)
并不影响其它
![](/icons/14230de.gif)
子进程
![](/icons/14230dou2.gif)
在Java中我们可以使用两种思路方法来实现这种要求
![](/icons/14230dou2.gif)
最简单
![](/icons/14230de.gif)
思路方法就是通过Runtime中
![](/icons/14230de.gif)
exec思路方法执行java
![](/icons/14230class.gif)
name
![](/icons/14230dou2.gif)
如果执行成功
![](/icons/14230dou.gif)
这个思路方法返回
![](/icons/14230yi.gif)
个Process对象
![](/icons/14230dou.gif)
如果执行失败
![](/icons/14230dou.gif)
将抛出
![](/icons/14230yi.gif)
个IOException
![](/icons/14230cuowu.gif)
![](/icons/14230dou2.gif)
下面让我们来看
![](/icons/14230yi.gif)
个简单
![](/icons/14230de.gif)
例子
![](/icons/14230dou2.gif)
// Test1.java文件
import java.io.*;
public
![](/icons/14230class.gif)
Test
{
public
![](/icons/14230static.gif)
void
![](/icons/14230main.gif)
(String
![](/icons/14230zhk2.gif)
args)
{
FileOutputStream fOut =
![](/icons/14230new.gif)
FileOutputStream("c:\\Test1.txt");
fOut.close
![](/icons/14230kh.gif)
;
![](/icons/14230System.gif)
.out.pr
![](/icons/14230int.gif)
ln("被
![](/icons/14230diaoyong.gif)
成功!");
}
}
// Test_Exec.java
public
![](/icons/14230class.gif)
Test_Exec
{
public
![](/icons/14230static.gif)
void
![](/icons/14230main.gif)
(String
![](/icons/14230zhk2.gif)
args)
{
Runtime run = Runtime.getRuntime
![](/icons/14230kh.gif)
;
Process p = run.exec("java test1");
}
}
通过java Test_Exec运行
![](/icons/14230chengxu.gif)
后
![](/icons/14230dou.gif)
发现在C盘多了个Test1.txt文件
![](/icons/14230dou.gif)
但在控制台中并未出现"被
![](/icons/14230diaoyong.gif)
成功!"
![](/icons/14230de.gif)
输出信息
![](/icons/14230dou2.gif)
因此可以断定
![](/icons/14230dou.gif)
Test已经被执行成功
![](/icons/14230dou.gif)
但
![](/icons/14230yinwei.gif)
某种原因
![](/icons/14230dou.gif)
Test
![](/icons/14230de.gif)
输出信息未在Test_Exec
![](/icons/14230de.gif)
控制台中输出
![](/icons/14230dou2.gif)
这个原因也很简单
![](/icons/14230dou.gif)
![](/icons/14230yinwei.gif)
使用exec建立
![](/icons/14230de.gif)
是Test_Exec
![](/icons/14230de.gif)
子进程
![](/icons/14230dou.gif)
这个子进程并没有自己
![](/icons/14230de.gif)
控制台
![](/icons/14230dou.gif)
因此
![](/icons/14230dou.gif)
它并不会输出任何信息
![](/icons/14230dou2.gif)
如果要输出子进程
![](/icons/14230de.gif)
输出信息
![](/icons/14230dou.gif)
可以通过Process中
![](/icons/14230de.gif)
getInputStream得到子进程
![](/icons/14230de.gif)
输出流(在子进程中输出
![](/icons/14230dou.gif)
在父进程中就是输入)
![](/icons/14230dou.gif)
然后将子进程中
![](/icons/14230de.gif)
输出流从父进程
![](/icons/14230de.gif)
控制台输出
![](/icons/14230dou2.gif)
具体
![](/icons/14230de.gif)
实现代码如下如示:
// Test_Exec_Out.java
import java.io.*;
public
![](/icons/14230class.gif)
Test_Exec_Out
{
public
![](/icons/14230static.gif)
void
![](/icons/14230main.gif)
(String
![](/icons/14230zhk2.gif)
args)
{
Runtime run = Runtime.getRuntime
![](/icons/14230kh.gif)
;
Process p = run.exec("java test1");
BufferedInputStream in =
![](/icons/14230new.gif)
BufferedInputStream(p.getInputStream
![](/icons/14230kh.gif)
);
BufferedReader br =
![](/icons/14230new.gif)
BufferedReader(
![](/icons/14230new.gif)
InputStreamReader(in));
String s;
while ((s = br.readLine
![](/icons/14230kh.gif)
) != null)
![](/icons/14230System.gif)
.out.pr
![](/icons/14230int.gif)
ln(s);
}
}
从上面
![](/icons/14230de.gif)
代码可以看出
![](/icons/14230dou.gif)
在Test_Exec_Out.java中通过按行读取子进程
![](/icons/14230de.gif)
输出信息
![](/icons/14230dou.gif)
然后在Test_Exec_Out中按每行进行输出
![](/icons/14230dou2.gif)
上面讨论
![](/icons/14230de.gif)
是如何得到子进程
![](/icons/14230de.gif)
输出信息
![](/icons/14230dou2.gif)
那么
![](/icons/14230dou.gif)
除了输出信息
![](/icons/14230dou.gif)
还有输入信息
![](/icons/14230dou2.gif)
既然子进程没有自己
![](/icons/14230de.gif)
控制台
![](/icons/14230dou.gif)
那么输入信息也得由父进程提供
![](/icons/14230dou2.gif)
我们可以通过 Process
![](/icons/14230de.gif)
getOutputStream思路方法来为子进程提供输入信息(即由父进程向子进程输入信息
![](/icons/14230dou.gif)
而不是由控制台输入信息)
![](/icons/14230dou2.gif)
我们可以看看如下
![](/icons/14230de.gif)
代码:
// Test2.java文件
import java.io.*;
public
![](/icons/14230class.gif)
Test
{
public
![](/icons/14230static.gif)
void
![](/icons/14230main.gif)
(String
![](/icons/14230zhk2.gif)
args)
{
BufferedReader br =
![](/icons/14230new.gif)
BufferedReader(
![](/icons/14230new.gif)
InputStreamReader(
![](/icons/14230System.gif)
.in));
![](/icons/14230System.gif)
.out.pr
![](/icons/14230int.gif)
ln("由父进程输入
![](/icons/14230de.gif)
信息:" + br.readLine
![](/icons/14230kh.gif)
);
}
}
// Test_Exec_In.java
import java.io.*;
public
![](/icons/14230class.gif)
Test_Exec_In
{
public
![](/icons/14230static.gif)
void
![](/icons/14230main.gif)
(String
![](/icons/14230zhk2.gif)
args)
{
Runtime run = Runtime.getRuntime
![](/icons/14230kh.gif)
;
Process p = run.exec("java test2");
BufferedWriter bw =
![](/icons/14230new.gif)
BufferedWriter(
![](/icons/14230new.gif)
OutputStreamWriter(p.getOutputStream
![](/icons/14230kh.gif)
));
bw.write("向子进程输出信息");
bw.flush
![](/icons/14230kh.gif)
;
bw.close
![](/icons/14230kh.gif)
; // 必须得关闭流
![](/icons/14230dou.gif)
否则无法向子进程中输入信息
//
![](/icons/14230System.gif)
.in.read
![](/icons/14230kh.gif)
;
}
}
从以上代码可以看出
![](/icons/14230dou.gif)
Test1得到由Test_Exec_In发过来
![](/icons/14230de.gif)
信息
![](/icons/14230dou.gif)
并将其输出
![](/icons/14230dou2.gif)
当你不加bw.flash
![](/icons/14230kh.gif)
和bw.close
![](/icons/14230kh.gif)
时
![](/icons/14230dou.gif)
信息将无法到达子进程
![](/icons/14230dou.gif)
也就是说子进程进入阻塞状态
![](/icons/14230dou.gif)
但由于父进程已经退出了
![](/icons/14230dou.gif)
因此
![](/icons/14230dou.gif)
子进程也跟着退出了
![](/icons/14230dou2.gif)
如果要证明这
![](/icons/14230yi.gif)
点
![](/icons/14230dou.gif)
可以在最后加上
![](/icons/14230System.gif)
.in.read
![](/icons/14230kh.gif)
![](/icons/14230dou.gif)
然后通过任务管理器(在windows下)查看java进程
![](/icons/14230dou.gif)
你会发现如果加上bw.flush
![](/icons/14230kh.gif)
和 bw.close
![](/icons/14230kh.gif)
![](/icons/14230dou.gif)
只有
![](/icons/14230yi.gif)
个java进程存在
![](/icons/14230dou.gif)
如果去掉它们
![](/icons/14230dou.gif)
就有两个java进程存在
![](/icons/14230dou2.gif)
这是
![](/icons/14230yinwei.gif)
![](/icons/14230dou.gif)
如果将信息传给Test2
![](/icons/14230dou.gif)
在得到信息后
![](/icons/14230dou.gif)
Test2就退出了
![](/icons/14230dou2.gif)
在这里有
![](/icons/14230yi.gif)
点需要介绍说明
![](/icons/14230yi.gif)
下
![](/icons/14230dou.gif)
exec
![](/icons/14230de.gif)
执行是异步
![](/icons/14230de.gif)
![](/icons/14230dou.gif)
并不会
![](/icons/14230yinwei.gif)
执行
![](/icons/14230de.gif)
某个
![](/icons/14230chengxu.gif)
阻塞而停止执行下面
![](/icons/14230de.gif)
代码
![](/icons/14230dou2.gif)
因此
![](/icons/14230dou.gif)
可以在运行 test2后
![](/icons/14230dou.gif)
仍可以执行下面
![](/icons/14230de.gif)
代码
![](/icons/14230dou2.gif)
exec思路方法经过了多次
![](/icons/14230de.gif)
重载
![](/icons/14230dou2.gif)
上面使用
![](/icons/14230de.gif)
只是它
![](/icons/14230de.gif)
![](/icons/14230yi.gif)
种重载
![](/icons/14230dou2.gif)
它还可以将命令和参数分开
![](/icons/14230dou.gif)
如exec("java.test2")可以写成exec("java", "test2")
![](/icons/14230dou2.gif)
exec还可以通过指定
![](/icons/14230de.gif)
环境变量运行区别配置
![](/icons/14230de.gif)
java虚拟机
![](/icons/14230dou2.gif)
除了使用Runtime
![](/icons/14230de.gif)
exec思路方法建立子进程外
![](/icons/14230dou.gif)
还可以通过ProcessBuilder建立子进程
![](/icons/14230dou2.gif)
ProcessBuilder
![](/icons/14230de.gif)
使用思路方法如下:
// Test_Exec_Out.java
import java.io.*;
public
![](/icons/14230class.gif)
Test_Exec_Out
{
public
![](/icons/14230static.gif)
void
![](/icons/14230main.gif)
(String
![](/icons/14230zhk2.gif)
args)
{
ProcessBuilder pb =
![](/icons/14230new.gif)
ProcessBuilder("java", "test1");
Process p = pb.start
![](/icons/14230kh.gif)
;
… …
}
}
在建立子进程上
![](/icons/14230dou.gif)
ProcessBuilder和Runtime类似
![](/icons/14230dou.gif)
区别
![](/icons/14230de.gif)
ProcessBuilder使用start
![](/icons/14230kh.gif)
思路方法启动子进程
![](/icons/14230dou.gif)
而Runtime使用exec思路方法启动子进程
![](/icons/14230dou2.gif)
得到Process后
![](/icons/14230dou.gif)
它们
![](/icons/14230de.gif)
操作就完全
![](/icons/14230yi.gif)
样
![](/icons/14230de.gif)
![](/icons/14230dou2.gif)
ProcessBuilder和Runtime
![](/icons/14230yi.gif)
样
![](/icons/14230dou.gif)
也可设置可执行文件
![](/icons/14230de.gif)
环境信息、工作目录等
![](/icons/14230dou2.gif)
下面
![](/icons/14230de.gif)
例子描述了如何使用ProcessBuilder设置这些信息
![](/icons/14230dou2.gif)
ProcessBuilder pb =
![](/icons/14230new.gif)
ProcessBuilder("Command", "arg2", "arg2", ''');
// 设置环境变量
Map
env = pb.environment
;
env.put("key1", "value1");
env.remove("key2");
env.put("key2", env.get("key1") + "_test");
pb.directory("..\abcd"); // 设置工作目录
Process p = pb.start
; // 建立子进程
延伸阅读
最新评论