java多进程_Java多进程编程
一个线程可以包含多个进程1.Java进程的创建Java提供了两种⽅法⽤来启动进程或其它程序:
(1)使⽤Runtime的exec()⽅法
(2)使⽤ProcessBuilder的start()⽅法
1.1 ProcessBuilder ProcessBuilder类是J2SE 1.5在java.lang中新添加的⼀个新类,此类⽤于创建操作系统进程,它提供⼀种启动和管理进程(也就是应⽤程序)的⽅法。在J2SE 1.5之前,都是由Process类处来实现进程的控制管理。
每个 ProcessBuilder 实例管理⼀个进程属性集。start() ⽅法利⽤这些属性创建⼀个新的 Process 实例。start() ⽅法可以从同⼀实例重复调⽤,以利⽤相同的或相关的属性创建新的⼦进程。
每个进程⽣成器管理这些进程属性:
命令 是⼀个字符串列表,它表⽰要调⽤的外部程序⽂件及其参数(如果有)。在此,表⽰有效的操作系统命令的字符串列表是依赖于系统的。例如,每⼀个总体变量,通常都要成为此列表中的元素,但有⼀些操作系统,希望程序能⾃⼰标记命令⾏字符串——在这种系统中,Java 实现可能需要命令确切地包含这两个元素。
环境 是从变量 到值 的依赖于系统的映射。初始值是当前进程环境的⼀个副本(请参阅 v())。
⼯作⽬录。默认值是当前进程的当前⼯作⽬录,通常根据系统属性 user.dir 来命名。
redirectErrorStream 属性。最初,此属性为 false,意思是⼦进程的标准输出和错误输出被发送给两个独⽴的流,这些流可以通过InputStream() 和 ErrorStream() ⽅法来访问。如果将值设置为 true,标准错误将与标准输出合并。这使得关联错误消息和相应的输出变得更容易。在此情况下,合并的数据可从 InputStream() 返回的流读取,⽽从
修改进程构建器的属性将影响后续由该对象的 start() ⽅法启动的进程,但从不会影响以前启动的进程或 Java ⾃⾝的进程。⼤多数错误检查由 start() ⽅法执⾏。可以修改对象的状态,但这样 start() 将会失败。例如,将命令属性设置为⼀个空列表将不会抛出异常,除⾮包含了 start()。
注意,此类不是同步的。如果多个线程同时访问⼀个 ProcessBuilder,⽽其中⾄少⼀个线程从结构上修改了其中⼀个属性,它必须 保持外部同步。
构造⽅法摘要
ProcessBuilder(List command)
利⽤指定的操作系统程序和参数构造⼀个进程⽣成器。
command)
利⽤指定的操作系统程序和参数构造⼀个进程⽣成器。
⽅法摘要
List command()
返回此进程⽣成器的操作系统程序和参数。
ProcessBuilder command(List command)
设置此进程⽣成器的操作系统程序和参数。
ProcessBuilder command)
设置此进程⽣成器的操作系统程序和参数。
File directory()
返回此进程⽣成器的⼯作⽬录。
ProcessBuilder directory(File directory)
设置此进程⽣成器的⼯作⽬录。
Map environment()
返回此进程⽣成器环境的字符串映射视图。
boolean redirectErrorStream()
通知进程⽣成器是否合并标准错误和标准输出。
ProcessBuilder redirectErrorStream(boolean redirectErrorStream)
设置此进程⽣成器的 redirectErrorStream 属性。
Process start()
使⽤此进程⽣成器的属性启动⼀个新进程。
1.2 Runtime 每个 Java 应⽤程序都有⼀个 Runtime 类实例,使应⽤程序能够与其运⾏的环境相连接。可以通过 getRuntime ⽅法获取当前运⾏时。
应⽤程序不能创建⾃⼰的 Runtime 类实例。但可以通过 getRuntime ⽅法获取当前Runtime运⾏时对象的引⽤。⼀旦得到了⼀个当前的Runtime对象的引⽤,就可以调⽤Runtime对象的⽅法去控制Java虚拟机的状态和⾏为。
Java代码 收藏代码
void addShutdownHook(Thread hook)
注册新的虚拟机来关闭挂钩。
int availableProcessors()
向 Java 虚拟机返回可⽤处理器的数⽬。
Process exec(String command)
在单独的进程中执⾏指定的字符串命令。
Process exec(String[] cmdarray)
在单独的进程中执⾏指定命令和变量。
Process exec(String[] cmdarray, String[] envp)
在指定环境的独⽴进程中执⾏指定命令和变量。
Process exec(String[] cmdarray, String[] envp, File dir)
在指定环境和⼯作⽬录的独⽴进程中执⾏指定的命令和变量。
Process exec(String command, String[] envp)
在指定环境的单独进程中执⾏指定的字符串命令。
Process exec(String command, String[] envp, File dir)
在有指定环境和⼯作⽬录的独⽴进程中执⾏指定的字符串命令。
void exit(int status)
通过启动虚拟机的关闭序列,终⽌当前正在运⾏的 Java 虚拟机。
long freeMemory()
返回 Java 虚拟机中的空闲内存量。
void gc()
运⾏垃圾回收器。
InputStream getLocalizedInputStream(InputStream in)
已过时。 从 JDK 1.1 开始,将本地编码字节流转换为 Unicode 字符流的⾸选⽅法是使⽤ InputStreamReader 和 BufferedReader 类。
OutputStream getLocalizedOutputStream(OutputStream out)
已过时。 从 JDK 1.1 开始,将 Unicode 字符流转换为本地编码字节流的⾸选⽅法是使⽤ OutputStreamWriter、BufferedWriter 和PrintWriter 类。
static Runtime getRuntime()
返回与当前 Java 应⽤程序相关的运⾏时对象。
void halt(int status)
强⾏终⽌⽬前正在运⾏的 Java 虚拟机。
void load(String filename)
加载作为动态库的指定⽂件名。
void loadLibrary(String libname)
加载具有指定库名的动态库。
long maxMemory()
返回 Java 虚拟机试图使⽤的最⼤内存量。
boolean removeShutdownHook(Thread hook)
取消注册某个先前已注册的虚拟机关闭挂钩。
void runFinalization()
运⾏挂起 finalization 的所有对象的终⽌⽅法。
static void runFinalizersOnExit(boolean value)
已过时。 此⽅法本⾝具有不安全性。它可能对正在使⽤的对象调⽤终结⽅法,⽽其他线程正在操作这些对象,从⽽导致不正确的⾏为或死锁。
long totalMemory()
返回 Java 虚拟机中的内存总量。
void traceInstructions(boolean on)
启⽤/禁⽤指令跟踪。
void traceMethodCalls(boolean on)
启⽤/禁⽤⽅法调⽤跟踪。
1.3 Process不管通过那种⽅法启动进程后,都会返回⼀个Process类的实例代表启动的进程,该实例可⽤来控制进程并获得相关信息。Process 类提供了执⾏从进程输⼊、执⾏输出到进程、等待进程完成、检查进程的退出状态以及销毁(杀掉)进程的⽅法:
void destroy()
杀掉⼦进程。
⼀般情况下,该⽅法并不能杀掉已经启动的进程,不⽤为好。
int exitValue()
返回⼦进程的出⼝值。
只有启动的进程执⾏完成、或者由于异常退出后,exitValue()⽅法才会有正常的返回值,否则抛出异常。
InputStream getErrorStream()
获取⼦进程的错误流。
如果错误输出被重定向,则不能从该流中读取错误输出。
InputStream getInputStream()
获取⼦进程的输⼊流。
可以从该流中读取进程的标准输出。
OutputStream getOutputStream()
获取⼦进程的输出流。
写⼊到该流中的数据作为进程的标准输⼊。
int waitFor()
导致当前线程等待,如有必要,⼀直要等到由该 Process 对象表⽰的进程已经终⽌。
2.多进程编程实例⼀般我们在java中运⾏其它类中的⽅法时,⽆论是静态调⽤,还是动态调⽤,都是在当前的进程中执⾏的,也就是说,只有⼀个java虚拟机实例在运⾏。⽽有的时候,我们需要通过java代码启动多个java⼦进程。这样做虽然占⽤了⼀些系统资源,但会使程序更加稳定,因为新启动的程序
是在不同的虚拟机进程中运⾏的,如果有⼀个进程发⽣异常,并不影响其它的⼦进程。
在Java中我们可以使⽤两种⽅法来实现这种要求。最简单的⽅法就是通过Runtime中的exec⽅法执⾏java classname。如果执⾏成功,这个⽅法返回⼀个Process对象,如果执⾏失败,将抛出⼀个IOException错误。下⾯让我们来看⼀个简单的例⼦。
通过java Test_Exec运⾏程序后,发现在C盘多了个⽂件,但在控制台中并未出现"被调⽤成功!"的输出信息。因此可以断
定,Test已经被执⾏成功,但因为某种原因,Test的输出信息未在Test_Exec的控制台中输出。这个原因也很简单,因为使⽤exec建⽴的是Test_Exec的⼦进程,这个⼦进程并没有⾃⼰的控制台,因此,它并不会输出任何信息。
如果要输出⼦进程的输出信息,可以通过Process中的getInputStream得到⼦进程的输出流(在⼦进程中输出,在⽗进程中就是输⼊),然后将⼦进程中的输出流从⽗进程的控制台输出。具体的实现代码如下如⽰:
从上⾯的代码可以看出,在Test_Exec_Out.java中通过按⾏读取⼦进程的输出信息,然后在Test_Exec_Out中按每⾏进⾏输出。 上⾯讨论的是如何得到⼦进程的输出信息。那么,除了输出信息,
还有输⼊信息。既然⼦进程没有⾃⼰的控制台,那么输⼊信息也得由⽗进程提供。我们可以通过Process的getOutputStream⽅法来为⼦进程提供输⼊信息(即由⽗进程向⼦进程输⼊信息,⽽不是由控制台输⼊信息)。我们可以看看如下的代码:
从以上代码可以看出,Test1得到由Test_Exec_In发过来的信息,并将其输出。当你不加bw.flash()和bw.close()时,信息将⽆法到达⼦进程,也就是说⼦进程进⼊阻塞状态,但由于⽗进程已经退出了,因此,⼦进程也跟着退出了。如果要证明这⼀点,可以在最后加上ad(),然后通过任务管理器(在windows下)查看java进程,你会发现如果加上bw.flush()和bw.close(),只有⼀个java进程存在,如果去掉它们,就有两个java进程存在。这是因为,如果将信息传给Test2,在得到信息后,Test2就退出了。在这⾥有⼀点需要说明⼀下,exec的执⾏是异步的,并不会因为执⾏的某个程序阻塞⽽停⽌执⾏下⾯的代码。因此,可以在运⾏test2后,仍可以执⾏下⾯的代码。
exec⽅法经过了多次的重载。上⾯使⽤的只是它的⼀种重载。它还可以将命令和参数分开,如exec("st2")可以写成exec("java", "test2")。exec还可以通过指定的环境变量运⾏不同配置的java虚拟机。
除了使⽤Runtime的exec⽅法建⽴⼦进程外,还可以通过ProcessBuilder建⽴⼦进程。ProcessBuilder的使⽤⽅法如下:
在建⽴⼦进程上,ProcessBuilder和Runtime类似,不同的ProcessBuilder使⽤start()⽅法启动⼦进程,⽽Runtime使⽤exec⽅法启动⼦进程。得到Process后,它们的操作就完全⼀样的。
ProcessBuilder和Runtime⼀样,也可设置可执⾏⽂件的环境信息、⼯作⽬录等。下⾯的例⼦描述了如何使⽤ProcessBuilder设置这些信息。
如对本⽂有所疑问,请点击进⼊脚本之家知识社区提问。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论