Java_Runtime&Process&ProcessBuilder
在Java中想调用外部程序,或者执行命令和可运行文件时,网上的典型实例一般都是通过Runtime.getTime().exec()
【 java.lang包】去执行相应的操作。看源码才发现还有Process和ProcessBuilder类,来具体看看它们的区别和用法。
一、Runtime类
Runtime类采用的饿汉式单例设计模式(定义了私有类变量和私有构造方法,通过静态方法返回该类的唯一实例)。每个 Java 应用程序都有一个 Runtime 类实例,使应用程序能够与其运行的环境相连接。应用程序不能创建自己的Runtime 类实例。只能通过 getRuntime 方法获取当前运行时对象的引用。
- 查看虚拟机相关状态
Runtime rt = Runtime.getRuntime(); //获取类的实例对象
System.out.println(rt.availableProcessors());// 返回可用于Java虚拟机的处理器数量
System.out.println(rt.freeMemory());// 返回Java虚拟机中的可用内存量 (单位:字节)
System.out.println(rt.maxMemory());// 返回Java虚拟机将尝试使用的最大内存量
System.out.println(rt.totalMemory());// 返回Java虚拟机中的内存总量
//--------------------------------------------------------------------------
// System中的gc(),exit(),load() 等都是调用了该类中的同名方法
rt.gc(); // 运行垃圾回收器
rt.exit(0); // 通过启动其关闭序列来终止当前正在运行的Java虚拟机,底层调用Shutdown.exit()实现
rt.halt(0); // 强制终止当前正在运行的Java虚拟机(杀进程)
- 通过钩子,保证java程序安全退出
Runtime rt = Runtime.getRuntime();
// java 1.8的写法
Thread t =new Thread(
() -> System.out.println(Thread.currentThread().getName()+" +++++++++ ")
);
rt.addShutdownHook(t); //注册新的虚拟机来关闭钩子
new Thread(
new Runnable() {
private int i;
@Override
public void run() {
for(;i<10;i++){
System.out.println(Thread.currentThread().getName()+" --- "+i);
}
}
}
).start();
//rt.exit(0); // 若使用exit() 会等待钩子运行后再进行退出
//rt.halt(0); // 若这使用此方法,直接强制终止当前虚拟机,不会执行钩子
//rt.removeShutdownHook(t); // 注册的钩子会被取消,不会打印 "+++++"
- 执行操作方法 Runtime.exec (返回用于管理子进程的新的Process对象 )
Process exec(String command)
在单独的进程中执行指定的字符串命令Peocess exec(String[] cmdarray)
在单独的进程中执行指定的命令和参数Process exec(String command, String[] envp)
在单独的进程中执行指定的字符串命令Process exec(String[] cmdarray, String[] envp)
在指定环境的单独进程中执行指定的命令和参数Process exec(String command, String[] envp, File dir)
在指定的环境和工作目录的单独进程中执行指定的字符串命令Process exec(String[] cmdarray, String[] envp, File dir)
在指定的环境和工作目录的单独进程中执行指定的命令和参数
这6个重载方法(方法名一样,参数个数不一样,参数类型不一样)。实际上2、4、5调用的都是6这个方法,而1、3调用的是方法5。先来看一下方法6中实现:
return new ProcessBuilder(cmdarray).environment(envp).directory(dir).start();
可以看出来,实际上Runtime.getRuntime().exec(...)是通过 ProcessBuilder.start()去实现创建进程的。再来看方法5:
if (command.length() == 0)
throw new IllegalArgumentException("Empty command");
StringTokenizer st = new StringTokenizer(command);
String[] cmdarray = new String[st.countTokens()];
for (int i = 0; st.hasMoreTokens(); i++)
cmdarray[i] = st.nextToken();
return exec(cmdarray, envp, dir);
首先是判断传入的命令参数长度是否等于0,是则抛出异常。然后通过StringTokenizer类对传入的命令字符串进行解析(这里使用的默认分隔符集,即" \t\n\r\f" :空格字符,制表符,换行字符,回车字符和换页符)。并将解析后的Token使用for循环赋值给String数组的每个元素,最后将数组传给方法6。所以1-6方法实质上传入String类型的参数和传入String []数组参数是一样的。不过传入String [] 的优势在于:如果String类型输入的命令缺少空格,将会导致运行的命令错误。
实例:
import java.io.*;
import java.util.concurrent.TimeUnit;
public class Test002 {
public static void main(String [] args){
Runtime rt = Runtime.getRuntime();
try {
//Process p = rt.exec("cmd /c dir /s/b | findstr \"Test[0-9]*.java\"");// 当前文件中查找Test开头含多个数字的java文件
//Process p1 = rt.exec(new String[]{"cmd", "/c", "javac"});
Process p1 = rt.exec("cmd /c java -version"); // 将会通过 errorStream输出相关信息
PrintContext error = new PrintContext(p1.getErrorStream(), "Error");
PrintContext print = new PrintContext(p1.getInputStream(), "Print");
error.start();
print.start();
/*BufferedReader br = new BufferedReader(new InputStreamReader(p1.getInputStream(), "GBK"));
String line;
while((line = br.readLine())!=null){
System.out.println(line);
}
System.out.println("---------");
p1.waitFor(1,TimeUnit.SECONDS); // 等待1 s
BufferedReader br1 = new BufferedReader(new InputStreamReader(p1.getErrorStream(), "GBK"));
String line1;
while((line1 = br1.readLine())!=null){
System.err.println(line1);
}*/
} catch (IOException e) {
e.printStackTrace();
}
}
}
class PrintContext extends Thread {
private InputStream is;
private String type;
public PrintContext(InputStream is, String type) {
this.is = is;
this.type = type;
}
public void run() {
BufferedReader br = null;
try {
// 控制台输出为GBK编码
br = new BufferedReader(new InputStreamReader(is,"GBK"));
String line;
while ((line = br.readLine()) != null) {
if (type.equals("Error")) {
System.out.println("Error:" + line);
} else {
System.out.println("Print:" + line);
}
}
} catch (IOException e) {
e.printStackTrace();
}finally {
if(br != null){
try{
br.close();
}catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
}
二、Process类
Process 类是一个抽象类,其内部提供了6个抽象方法。用于执行进程输入,执行到进程的输出,等待进程完成,检查进程的退出状态以及破坏(杀死)进程的方法。创建的子进程没有自己的终端或控制台。 其所有的标准I / O(即标准输入,标准输出,标准错误)操作将被重定向到父进程。 父进程使用流将输入提供给子进程并从子进程获取输出。 因为一些本地平台只为标准输入和输出流提供有限的缓冲区大小,因此无法及时写入输入流或读取子进程的输出流可能导致子进程阻塞甚至死锁。
Runtime rt = Runtime.getRuntime();
Process p,p1=null;
try {
p = rt.exec("notepad.exe");
if(p.isAlive()){ // 判断Process进程是否存活
System.out.println(" p start...");
try {
p.waitFor(3, TimeUnit.SECONDS); // 等待3秒
p1 = rt.exec("cmd /c dir");
System.out.println(" p1 start...");
} catch (InterruptedException e) {
e.printStackTrace();
}
p.destroy(); // 杀死子进程
}
p1.waitFor(); // 导致当前线程等待,如有必要,直到由此 Process对象表示的进程已终止
System.out.println("p1 wait done");
p1.destroy();
System.out.println("p:"+p.exitValue()); // 1 非正常退出
System.out.println("p1:"+p1.exitValue()); // 0 正常退出
} catch (IOException|InterruptedException e) {
e.printStackTrace();
}
三、ProcessBuilder类
该类是一个不可变类,用于创建操作系统进程。每个ProcessBuilder实例管理进程属性的集合,start()方法使用这些属性创建一个新的Process实例。ProcessBuilder有个带参构造方法:
ProcessBuilder(List<String> command) 构造具有指定操作系统程序和参数的进程构建器
ProcessBuilder(String... command) 构造具有指定操作系统程序和参数的进程构建器
其实这两个的构造方法区别也不是很大,一个是传入List<String>
类型的参数然后初始化,另一个是传入可变的String类型参数,初始化List对象,将参数add到ArraysList里。所以ProcessBuilder不能像Runtime一样直接将整句的命令作为参数传参。
ProcessBuilder pb = new ProcessBuilder("notepad.exe");
try {
pb.directory(new File("E:\\WorkProjects")); // 设置进程构建器的工作目录
pb.command("cmd","/c","dir"); // 重新设置命令参数
Process p = pb.start(); // 运行进程
System.out.println(pb.directory().getPath()); // 获取进程构建器的工作目录路径
List<String> c = pb.command(); // 获取命令参数
Iterator<String> it = c.iterator();
while(it.hasNext()){
System.out.print(it.next()+"\t");// cmd /c dir
}
p.destroy();
} catch (IOException e) {
e.printStackTrace();
}
Java_Runtime&Process&ProcessBuilder的更多相关文章
- [Java][Android][Process] ProcessBuilder与Runtime差别
在Android中想要进行Ping,在不Root机器的情况下似乎还仅仅能进行底层命调用才干实现. 由于在Java中要进行ICMP包发送须要Root权限. 于是仅仅能通过创建进程来攻克了.创建进程在Ja ...
- Java中ProcessBuilder应用实例
系列说明 浅析Java.lang.Runtime类 浅析Java.lang.Process类 浅析Java.lang.ProcessBuilder类 可以使用java中的ProcessBuilder执 ...
- [Java][Android][Process] 暴力的服务能够解决一切,暴力的方式运行命令行语句
不管是在Java或者Android中运行命令行语句殊途同归都是创建一个子进程运行调用可运行文件运行命令.类似于Windows中的CMD一样. 此时你有两种方式运行:ProcessBuilder与Run ...
- 浅析ProcessBuilder
概述 ProcessBuilder类是J2SE 1.5在java.lang中新添加的一个新类,此类用于创建操作系统进程,它提供一种启动和管理进程(也就是应用程序)的方法.在J2SE 1.5之前,都是由 ...
- 多线程 调用多线程的方法 Runtime与ProcessBuilder
一般我们使用Java运行其他类中的方法的时候,无论是静态调用还是动态调用,都是在当前的进程中执行的.也就是只有一个Java虚拟机实例在运行.有时候需要通过Java代码启动多个Java子进程,这样做会消 ...
- Android随笔之——静默安装、卸载
随笔之所以叫随笔,就是太随意了,说起来,之前的闹钟系列随笔还没写完,争取在十月结束之前找时间把它给写了吧.今天要讲的Android APK的静默安装.卸载.网上关于静默卸载的教程有很多,更有说要调用隐 ...
- java执行命令行
List<String> command = new ArrayList<String>(); command.add("ping"); ProcessBu ...
- PDF解决方案(3)--PDF转SWF
相关专题链接 PDF解决方案(1)--文件上传 PDF解决方案(2)--文件转PDF PDF解决方案(3)--PDF转SWF PDF解决方案(4)--在线浏览 前言:上一篇中介绍了上传的文件转PDF, ...
- Scala入门系列(十二):隐式转换
引言 Scala提供的隐式转换和隐式参数功能,是非常有特色的功能.是Java等编程语言所没有的功能.它可以允许你手动指定,将某种类型的对象转换成其他类型的对象.通过这些功能可以实现非常强大而且特殊的功 ...
随机推荐
- apply和call与this
函数本身的apply方法,改变this指向哪个对象: function getAge() { var y = new Date().getFullYear(); return y - this.bir ...
- BEX5下增加sessionStorage监听器实现页面间数据刷新
场景: A页面修改了数据,希望B页面能进行及时的同步前端数据,但是假如当A页面修改保存后,去获得B页面的model对象,会增加开发的难度,同时A页面也不能重复利用:假如在B页面的激活事件里面写刷新代码 ...
- 【数学建模】灰色系统理论II-Verhulst建模-GM(1,N)-GM(2,1)建模
灰色系统理论中,GM(1,1)建模很常用,但他是有一定适应范围的. GM(1,1)适合于指数规律较强的序列,只能描述单调变化过程.对于具有一定随机波动性的序列,我们考虑使用Verhulst预测模型,或 ...
- 记录腾讯云中矿机病毒处理过程(重装系统了fu*k)
刚想学学kafka,登录与服务器看看把,谁知ssh特别慢,很奇怪,我以为是我网速问题,断了wifi,换了网线,通过iterm想要ssh root@x.x.x.x,但是上不去? 就tm的很奇怪了,登录腾 ...
- Codeforces Round #551 (Div. 2) 题解
CF1153A 直接做啊,分类讨论即可 #include<iostream> #include<string.h> #include<string> #includ ...
- HTTP 404 Not Found Error with .woff or .woff2 Font Files
如果是 ERR_ABORTED 404 (Not Found) WOFF2,则有可能是文件不存在
- poj 2955 Brackets (区间dp 括号匹配)
Description We give the following inductive definition of a “regular brackets” sequence: the empty s ...
- 如何修改hosts文件
如何修改hosts文件 1.进入路径 C:\Windows\System32\drivers\etc 2.拷贝hosts文件到其他地方3.修改拷贝的hosts文件,右键用记事本打开4.直接修改或添加 ...
- luoguP4705 玩游戏
好好玩 即对于k∈[1,t] 求(ax+by)^k 以下图片均来自于: 在Ta的博客查看 一 二项式展开: 设: 那么: 可以卷积了 二 求: (PS:随机序列的0~k次方和,这是一个经典问题.) 我 ...
- 洛谷P1233 木棍加工题解 LIS
突然发现自己把原来学的LIS都忘完了,正好碰见这一道题.|-_-| \(LIS\),也就是最长上升子序列,也就是序列中元素严格单调递增,这个东西有\(n^{2}\)和\(nlog_{2}n\)两种算法 ...