java调用process线程阻塞问题

背景

项目需求中涉及java调用.bat文件进行图像处理,先直接上简略版程序

 1     public void draw(){
 2
 3         //调用bat脚本进行图像处理
 4         Process process = null;
 5         InputStream in = null;
 6         try {
 7             process = Runtime.getRuntime().exec("startup.bat");
 8
 9             //输出测试
10 //            in = process.getInputStream();
11 //            String line;
12 //            BufferedReader br = new BufferedReader(new InputStreamReader(in));
13 //            while ((line = br.readLine()) != null) {
14 //                System.out.println(line);
15 //            }
16
17             //等待
18             process.waitFor();
19
20         } catch (Exception e) {
21
22         } finally {
23             process.destroy();
24         }
25     }

JAVA使用遇到的问题描述

  一般需要调用系统命令时,大部分人第一反应肯定是使用Runtime.getRuntime().exec(command)返回一个process对象,再调用process.waitFor()来等待命令执行结束,获取执行结果。

  调试的时候发现很奇怪的现象,process.waitFor();一直没有结束,导致线程阻塞再次,强行关闭程序后,发现图像处理只进行了一部分。

  于是打算打印process的输出,看是否是图像脚本出现异常。

  在启用输出测试的下发代码后,发现process的输出一切正常,process.waitFor()一直再等待,并未结束,此时强行关闭程序后,发现图像处理并之前多操作了一部分

  根据现象并查看了JDK的帮助文档,如下

因此,可以得出结论:如果外部程序不断在向标准输出流(对于jvm来说就是输入流)和标准错误流写数据,而JVM不读取的话,当缓冲区满之后将无法继续写入数据,最终造成阻塞在waitFor()这里。

解决方法:在waitFor()之前,利用单独两个线程,分别处理process的getInputStream()和getErrorSteam(),防止缓冲区被撑满,导致阻塞;

修改后代码

 1 public class test {
 2
 3     public void draw(){
 4
 5         //调用bat脚本进行图像处理
 6         Process process = null;
 7         InputStream in = null;
 8         try {
 9             process = Runtime.getRuntime().exec("startup.bat");
10
11             //输出测试
12 //            in = process.getInputStream();
13 //            String line;
14 //            BufferedReader br = new BufferedReader(new InputStreamReader(in));
15 //            while ((line = br.readLine()) != null) {
16 //                System.out.println(line);
17 //            }
18             //新启两个线程
19             new DealProcessSream(process.getInputStream()).start();
20             new DealProcessSream(process.getErrorStream()).start();
21
22             process.waitFor();
23
24         } catch (Exception e) {
25
26         } finally {
27             process.destroy();
28         }
29     }
30 }
 1 public class DealProcessSream extends Thread {
 2     private InputStream inputStream;
 3
 4     public DealProcessSream(InputStream inputStream) {
 5         this.inputStream = inputStream;
 6     }
 7
 8     public void run() {
 9         InputStreamReader inputStreamReader = null;
10         BufferedReader br = null;
11         try {
12             inputStreamReader = new InputStreamReader(
13                     inputStream);
14             br = new BufferedReader(inputStreamReader);
15             // 打印信息
16 //            String line = null;
17 //            while ((line = br.readLine()) != null) {
18 //                System.out.println(line);
19 //            }
20             // 不打印信息
21            while (br.readLine() != null);
22         } catch (IOException ioe) {
23             ioe.printStackTrace();
24         }finally {
25             try {
26                 br.close();
27                 inputStreamReader.close();
28             } catch (IOException e) {
29                 e.printStackTrace();
30             }
31         }
32
33     }
34 }

原文地址:https://www.cnblogs.com/MacrossFT/p/12038479.html

时间: 2024-11-07 03:50:31

java调用process线程阻塞问题的相关文章

Java调用 shell脚本阻塞

Java在调用Shell时,要不断读取进程中标准输出和错误输出流的信息,否则缓冲区被写满就会造成子进程阻塞而无法继续运行下去,可起两个线程不断读取标准输出.错误流信息而不被阻塞 import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.UnsupportedEncodingExcept

Java基础之线程阻塞栈

阻塞栈,与阻塞队列相似.不同点在于栈是“后入先出”的结构,每次操作的是栈顶,而队列是“先进先出”的结构,每次操作的是队列头:Java为阻塞栈定义了接口:java.util.concurrent.BlockingDeque,其实现类也比较多 package unit_fifteen; import java.util.concurrent.BlockingDeque; import java.util.concurrent.LinkedBlockingDeque; /** * Java线程:新特征

Java基础之线程阻塞队列

阻塞队列是Java线程新特征中的内容,Java定义了阻塞队列的接口java.util.concurrent.BlockingQueue,阻塞队列的概念是,一个指定长度的队列,如果队列满了,添加新元素的操作会被阻塞等待,直到有空位为止.同样,当队列为空时候,请求队列元素的操作同样会阻塞等待,直到有可用元素为止 阻塞队列还有很多实现类,用来满足各种复杂的需求:BlockingQueue.ArrayBlockingQueue, DelayQueue, LinkedBlockingQueue, Prio

线程阻塞和挂起(网络收集)

线程阻塞 线程在运行的过程中因为某些原因而发生阻塞,阻塞状态的线程的特点是:该线程放弃CPU的使用,暂停运行,只有等到导致阻塞的原因消除之后才回复运行.或者是被其他的线程中断,该线程也会退出阻塞状态,同时抛出InterruptedException. 一般线程中的阻塞: A.线程执行了Thread.sleep(int millsecond);方法,当前线程放弃CPU,睡眠一段时间,然后再恢复执行 B.线程执行一段同步代码,但是尚且无法获得相关的同步锁,只能进入阻塞状态,等到获取了同步锁,才能回复

java进阶07 线程的让步与阻塞与同步

前面介绍了线程的一些基本知识,现在来说下线程的让步,阻塞,和同步 先说说让步 所谓让步,就是让调用者的线程暂停,让其他线程重新竞争CPU,包括调用者. 先看看代码 package Thread; public class ThreadYield { public static void main(String[] args){ MyThread5 rthread=new MyThread5(); Thread thread1=new Thread(rthread); Thread thread2

JAVA并发实现四(守护线程和线程阻塞)

守护线程     Java中有两类线程:User Thread(用户线程).Daemon Thread(守护线程) 用户线程即运行在前台的线程,而守护线程是运行在后台的线程. 守护线程作用是为其他前台线程的运行提供便利服务,而且仅在普通.非守护线程仍然运行时才需要,比如垃圾回收线程就是一个守护线程.当VM检测仅剩一个守护线程,而用户线程都已经退出运行时,VM就会退出,因为没有如果没有了被守护者,也就没有继续运行程序的必要了.如果有非守护线程仍然存活,VM就不会退出. 守护线程并非只有虚拟机内部提

多线程之Java线程阻塞与唤醒

线程的阻塞和唤醒在多线程并发过程中是一个关键点,当线程数量达到很大的数量级时,并发可能带来很多隐蔽的问题.如何正确暂停一个线程,暂停后又如何在一个要求的时间点恢复,这些都需要仔细考虑的细节.在Java发展史上曾经使用suspend().resume()方法对于线程进行阻塞唤醒,但随之出现很多问题,比较典型的还是死锁问题.如下代码,主要的逻辑代码是主线程启动线程mt一段时间后尝试使用suspend()让线程挂起,最后使用resume()恢复线程.但现实并不如愿,执行到suspend()时将一直卡住

Java线程阻塞中断和LockSupport的常见问题

上周五和周末,工作忙里偷闲,在看java cocurrent中也顺便再温故了一下Thread.interrupt和java 5之后的LockSupport的实现. 在介绍之前,先抛几个问题. Thread.interrupt()方法和InterruptedException异常的关系?是由interrupt触发产生了InterruptedException异常? Thread.interrupt()会中断线程什么状态的工作? RUNNING or BLOCKING? 一般Thread编程需要关注

java调用shell process has not exited

* http://kingj.iteye.com/blog/1420586 ,出现了 java.lang.IllegalThreadStateException: process has not exited        at java.lang.Win32Process.exitValue(Native Method) 异常,后台一百度发现,jdk实现process时,调用外部命令不是同步的调用,而是异步执行.所以tree命令还没有执行成功就返回,jdk抛出异常. int status=pr