Java动态编译(二)
在上一篇(Java动态编译(一))中我们提到了动态编译的三种方法,在这篇文章中讲解一些扩展的知识。
上面的程序并没有按照我们预想的那样列出g盘下的目录,而是挂起了,为什么会出现这种情况呢?java文档上说,创建进程的方法可能无法针对某些本机平台上的特定进程很好地工作,比如,本机窗口进程,守护进程,Microsoft Windows 上的 Win16/DOS 进程,或者 shell 脚本。创建的子进程没有自己的终端或控制台。它的所有标准io(即 stdin、stdout 和 stderr)操作都将通过三个流 (getOutputStream()、getInputStream() 和 getErrorStream()) 重定向到父进程。父进程使用这些流来提供到子进程的输入和获得从子进程的输出。因为有些本机平台仅针对标准输入和输出流提供有限的缓冲区大小,如果读写子进程的输出流或输入流迅速出现失败,则可能导致子进程阻塞,甚至产生死锁。
当进程启动后,就会打开标准输出流和错误输出流准备输出,当进程结束时,就会关闭他们。在举例1中,由于标准输出流有数据需要输出,但是我们却没有读取其中的数据,标准输出流就会一直等待数据被读取,程序挂起。
举例2.处理标准输出流
当我们处理了标准输出后,则程序可以正常运行了。但是,如果我们的命令是错误的,那么情况又会如何呢?即这里将dir修改成dira,然后执行。程序仍然可以正常运行,只不过结束的时候的exitVal不再是0。
为什么会出现这种情况呢?这里就是当我们执行程序的时候,先打开的是标准输出流,然后等待我们从中读取数据,而我们对需要读取的数据做了读取处理。那么当接下来打开错误输出流的时候,尽管没有被读取,但是却不再阻塞,程序异常终止。
但是,如果命令是正确的(即dira已经改回dir)再将process.getInputStream()修改成process.getErrorStream()呢?这次程序又一起挂起了。这是由于标准输出流是先打开并需要输出而,但是却并没有被读取;读取的是错误输出流,那么此时标准输出流的数据没有被读取导致程序不会结束。
为了解决这个问题,可以根据输出的实际先后,先读取标准输出流,然后读取错误输出流。
但是,很多时候不能很明确的知道输出的先后,特别是要操作标准输入的时候,情况就会更为复杂。这时候可以采用线程来对标准输出、错误输出和标准输入进行分别处理,根据他们之间在业务逻辑上的关系决定读取那个流或者写入数据。
针对标准输出流和错误输出流所造成的问题,还可以使用ProcessBuilder的redirectErrorStream()方法将他们合二为一,这时候只要读取标准输出的数据就可以了。
举例3.使用多线程
<<OVER>>