Java中Runtime运行时环境机制总结

最近由于在编码中需要在java代码中执行linux命令,使用到了Runtime类的一些方法,也出现几个小bug,所以趁这个机会对Runtime也就是运行时环境这个类进行总结。

Runtime.getRuntime()能得到一个Runtime对象实例,也就是当前运行时环境实例,这个玩艺是什么东西?java中称为虚拟机的运行时环境,这个说法很抽象,我在网上百度了很久,没有确切的说法,我感觉这个Runtime对象实例其实更像是java 程序的进程的概念,当然只是我初步的想法,后续找到更多资料可能就发现错了。

1.去看下Runtime的源码,首先可以发现Runtime使用了单例的设计模式

private static Runtime currentRuntime = newRuntime();

public static Runtime getRuntime() {

       return currentRuntime;

    }

private Runtime() {}

--上面就是典型的单实例设计模式,所以在java程序中不同线程通过调用Runtime.getRuntime()获得的是同一个对象实例,也就是说一个java进程中只有一个Runtime实例

2. Runtime的一些方法

主要使用的方法就是exec,在Runtime中,exec方法进行了多次重载

public Process exec(String command) throwsIOException

public Process exec(String command,String[] envp)

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

public Process exec(String cmdarray[])throws IOException

比较多用到的是第一个和第四个,第三个有两个参数String[] envp, File dir,这是什么?前者是指环境变量字符串,后者是指工作目录。这一点跟进程很相似。不指定这两个参数时默认是当前环境和当前目录。再看看这个方法的返回值是Process类型,这个是什么?其实是子进程的一个管理器实例,也就是说我们在调用exec方法时,实际上是创建了一个子进程,并且由该子进程执行我们传入的命令。这点可以明显从exec源码看出

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

       throws IOException {

       return new ProcessBuilder(cmdarray)

           .environment(envp)

           .directory(dir)

           .start();

}

-- ProcessBuilder创建子进程,并设置环境变量和工作目录,然后start。可见父进程子进程的概念在java中还是存在的。

3. Process的主要方法

destroy()

   杀掉子进程。

 exitValue()

   返回子进程的出口值。

 InputStream getErrorStream()

   获得子进程的错误流。

 InputStream getInputStream()

   获得子进程的输入流。

 OutputStream getOutputStream()

   获得子进程的输出流。

 waitFor()

   导致当前线程等待,如果必要,一直要等到由该 Process 对象表示的进程已经终止。

 

--一般执行linux命令使用比较多的是waitFor(),诸塞等待子进程完成该linux命令。然后再继续线程后续的代码。

 

--以上基本简单把Runtime的应用机制介绍了下,虽然不算深入,但是平常简单的调用linux命令这种简单的工作就能做到基本心里有底了,下面继续说说在应用过程中遇到的小坑

坑一:如何在exec执行多条linux命令

不熟悉时可能会把一段linux命令当作输入直接执行,然后发现并没有执行,这是为什么呢?比如”mv dir1/*.* dir2;wait;gzip dir2/*.*;” 这段命令直接在linux上直接执行是没问题的,但是放到exec执行会发现根本没能执行,原因是exec最终会对command进行一次字符串分割,默认以” \t\n\r\f”(前有一个空格,引号不是)为分割符,上面语句不符合格式。

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

       throws IOException {

       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);

}

正确用法是用&&连接起来”mv dir1/*.* dir2&&wait&&gzip dir2/*.*”,或则把三个命令加入String数组,调用publicProcess exec(String cmdarray[]) throws IOException这个重载方法。

 

坑二:为什么如果在java代码中不调用waitFor()阻塞等待linux中命令执行结束会出现部分命令并没有执行的情况。

比如我遇到的问题,在java中执行了下面两行代码

Runtime.getRuntime().exec(“mv dir1/file.txtdir2”);

Runtime.getRuntime().exec(“gzip dir2/ file.txt”);

多线程执行一段时间后会发现有部分文件没有按希望去压缩,这是什么原因,百思不得其解,目前还没搞得太清楚,初步认为是主进程创建了两个子进程,如果不诸塞的话,可能当进程1的文件还没挪到dir2,进程2已经执行了,所以这部分文件没有按希望进行压缩。但是为什么进程二没有报文件不存在的错误呢?这个也是跟疑问。不管怎么说解决之道就是加阻塞。

Runtime.getRuntime().exec(“mv dir1/file.txtdir2”) .waitFor();

Runtime.getRuntime().exec(“gzip dir2/ file.txt”).waitFor();

加上.waitFor()后,发现之前的问题解决了,文件全部都进行了压缩。

 

--补充修正

如何在exec执行多条linux命令

调用public Process exec(String cmdarray[]) throws IOException这个重载方法是无法执行多条命令的,数组的作用只是让你手工把命令和传入参数切割开来,以便后续子进程的调用,另外”mv dir1/*.* dir2&&wait&&gzip dir2/*.*”这种用&&连接的多命令也是不可用的,第调用多条命令只能一个个命令执行,或则把多条命令写入脚本,exec直接执行该脚本。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值