随笔 - 312, 文章 - 14, 评论 - 1393, 引用 - 0

导航

<2008年5月>
27282930123
45678910
11121314151617
18192021222324
25262728293031
1234567

公告

关注我的新浪微博

我的著作









常用链接

留言簿(126)

我参与的团队

随笔分类(818)

随笔档案(310)

文章分类(1)

文章档案(8)

相册

ADSL、3G查询

CSDN

eclipse

ibm

Java EE

Linux

Web

云服务

代理网站

关注的网站

协议

喜欢的Blog

国内广告平台

图书出版

在线培训

开发工具

微博客户端

手机铃声

操作系统

  • ReactOS
  • 一个与windowXP/2003兼容的操作系统

数学

文件格式

源码资源

移动(Mobile)

编程语言

英语学习

最新随笔

搜索

  •  

积分与排名

  • 积分 - 1969740
  • 排名 - 6

最新评论

阅读排行榜

评论排行榜

Java的多进程运行模式分析

本文为原创,如需转载,请注明作者和出处,谢谢!

本文曾发表于天极网:http://dev.yesky.com/284/2659284.shtml

    一般我们在java中运行其它类中的方法时,无论是静态调用,还是动态调用,都是在当前的进程中执行的,也就是说,只有一个java虚拟机实例在运行。而有的时候,我们需要通过java代码启动多个java子进程。这样做虽然占用了一些系统资源,但会使程序更加稳定,因为新启动的程序是在不同的虚拟机进程中运行的,如果有一个进程发生异常,并不影响其它的子进程。

在Java中我们可以使用两种方法来实现这种要求。最简单的方法就是通过Runtime中的exec方法执行java classname。如果执行成功,这个方法返回一个Process对象,如果执行失败,将抛出一个IOException错误。下面让我们来看一个简单的例子。

// Test1.java文件
import java.io.*;
public class Test
{
public static void main(String[] args)
{
FileOutputStream fOut 
= new FileOutputStream("c:\\Test1.txt");
fOut.close();
System.out.println(
"被调用成功!");
}
}

// Test_Exec.java
public class Test_Exec
{
public static void main(String[] args)
{
Runtime run 
= Runtime.getRuntime();
Process p 
= run.exec("java test1");
}
}

通过java Test_Exec运行程序后,发现在C盘多了个Test1.txt文件,但在控制台中并未出现"被调用成功!"的输出信息。因此可以断定,Test已经被执行成功,但因为某种原因,Test的输出信息未在Test_Exec的控制台中输出。这个原因也很简单,因为使用exec建立的是Test_Exec 的子进程,这个子进程并没有自己的控制台,因此,它并不会输出任何信息。

如果要输出子进程的输出信息,可以通过Process中的getInputStream得到子进程的输出流(在子进程中输出,在父进程中就是输入),然后将子进程中的输出流从父进程的控制台输出。具体的实现代码如下如示:

// Test_Exec_Out.java
import java.io.*;
public class Test_Exec_Out
{
public static void main(String[] args)
{
Runtime run 
= Runtime.getRuntime();
Process p 
= run.exec("java test1");
BufferedInputStream in 
= new BufferedInputStream(p.getInputStream());
BufferedReader br 
= new BufferedReader(new InputStreamReader(in));
String s;
while ((s = br.readLine()) != null)
System.out.println(s);
}
}


从上面的代码可以看出,在Test_Exec_Out.java中通过按行读取子进程的输出信息,然后在Test_Exec_Out中按每行进行输出。上面讨论的是如何得到子进程的输出信息。那么,除了输出信息,还有输入信息。既然子进程没有自己的控制台,那么输入信息也得由父进程提供。我们可以通过 Process的getOutputStream方法来为子进程提供输入信息(即由父进程向子进程输入信息,而不是由控制台输入信息)。我们可以看看如下的代码:

// Test2.java文件
import java.io.*;
public class Test
{
public static void main(String[] args)
{
BufferedReader br 
= new BufferedReader(new InputStreamReader(System.in));
System.out.println(
"由父进程输入的信息:" + br.readLine());
}
}

// Test_Exec_In.java
import java.io.*;
public class Test_Exec_In
{
public static void main(String[] args)
{
Runtime run 
= Runtime.getRuntime();
Process p 
= run.exec("java test2");
BufferedWriter bw 
= new BufferedWriter(new OutputStreamWriter(p.getOutputStream()));
bw.write(
"向子进程输出信息");
bw.flush();
bw.close(); 
// 必须得关闭流,否则无法向子进程中输入信息
// System.in.read();
 }
}

从以上代码可以看出,Test1得到由Test_Exec_In发过来的信息,并将其输出。当你不加bw.flash()和bw.close()时,信息将无法到达子进程,也就是说子进程进入阻塞状态,但由于父进程已经退出了,因此,子进程也跟着退出了。如果要证明这一点,可以在最后加上 System.in.read(),然后通过任务管理器(在windows下)查看java进程,你会发现如果加上bw.flush()和 bw.close(),只有一个java进程存在,如果去掉它们,就有两个java进程存在。这是因为,如果将信息传给Test2,在得到信息后, Test2就退出了。在这里有一点需要说明一下,exec的执行是异步的,并不会因为执行的某个程序阻塞而停止执行下面的代码。因此,可以在运行 test2后,仍可以执行下面的代码。
exec方法经过了多次的重载。上面使用的只是它的一种重载。它还可以将命令和参数分开,如exec("java.test2")可以写成exec("java", "test2")。exec还可以通过指定的环境变量运行不同配置的java虚拟机。

除了使用Runtime的exec方法建立子进程外,还可以通过ProcessBuilder建立子进程。ProcessBuilder的使用方法如下:

// Test_Exec_Out.java
import java.io.*;
public class Test_Exec_Out
{
public static void main(String[] args)
{
ProcessBuilder pb 
= new ProcessBuilder("java""test1");
Process p 
= pb.start();
… …
}
}

在建立子进程上,ProcessBuilder和Runtime类似,不同的ProcessBuilder使用start()方法启动子进程,而Runtime使用exec方法启动子进程。得到Process后,它们的操作就完全一样的。

ProcessBuilder和Runtime一样,也可设置可执行文件的环境信息、工作目录等。下面的例子描述了如何使用ProcessBuilder设置这些信息。

ProcessBuilder pb = new ProcessBuilder("Command""arg2""arg2"''');
// 设置环境变量
Map<String, String> env = pb.environment();
env.put(
"key1""value1");
env.remove(
"key2");
env.put(
"key2", env.get("key1"+ "_test");
pb.directory(
"..\abcd"); // 设置工作目录
Process p = pb.start(); // 建立子进程




Android开发完全讲义(第2版)(本书版权已输出到台湾)

http://product.dangdang.com/product.aspx?product_id=22741502



Android高薪之路:Android程序员面试宝典 http://book.360buy.com/10970314.html


新浪微博:http://t.sina.com.cn/androidguy   昵称:李宁_Lining

posted on 2008-05-10 19:02 银河使者 阅读(2976) 评论(1)  编辑  收藏 所属分类: java 原创

评论

# re: Java的多进程运行模式分析[未登录]  回复  更多评论   

学习 http://www.dwww.cn
2009-06-19 21:15 | hello java

只有注册用户登录后才能发表评论。


网站导航: