最近用ffmpeg 监听文件夹批量转化视频文件,在调用 runtime.exec()多个ffmpeg.exe进程启动但是挂起,java程序关闭后这些进程开始工作。网上找了文章解释如下:
Java Runtime exec can hang
The next version of Savant is going to focus heavily on the stand-alone runtime and support for dialects and plugins. Supporting all that is largely handled by using a simple executor framework I wrote around Java 1.4 and lower’s Runtime.exec method. A few things to keep in mind when using this:
Always read from the streams prior to calling waitFor. Otherwise you could end up waiting forever on Windows and other OS platforms whose I/O buffers can’t store enough from standard out and standard error to ensure the program has finished. These platforms will pause the execution of whatever is running until something reads the buffered content from standard out and standard error. I would imagine all platforms suffer from this, but some platforms have larger buffers than others. Needless to say, always read from the streams first.
Always read from standard error first. I ran across a bug where some OS platforms will always open standard out, but never close it. What this means is that if you read from standard out first and the process only writes to standard error, you’ll hang forever waiting to read. If you read from standard error first, you’ll always be okay on these platforms because the OS seems to shutdown standard error. I think however, that the best way to handle all cases is to check both standard error and standard out for readiness and only read from them if they have something to offer. The downside I could see here is that error isn’t ready, but eventually will be.
可以看出:
永远要在调用waitFor()方法之前读取数据流
永远要先从标准错误流中读取,然后再读取标准输出流
于是将waitFor()方法放在读取数据流后调用,目前没有发现什么问题。
我们的程序一开始就是exec完了接着waitFor(),但bat文件执行不完整:
Process proc = Runtime.getRuntime().exec(cmd);
proc.waitFor();
后面的build中在waitFor()之前读取了数据流,bat文件就可以完整执行了:
Process proc = Runtime.getRuntime().exec(cmd);
StreamGobbler errorGobbler = new StreamGobbler(proc.getErrorStream(), "Error");
StreamGobbler outputGobbler = new StreamGobbler(proc.getInputStream(), "Output");
errorGobbler.start();
outputGobbler.start();
proc.waitFor();
class StreamGobbler extends Thread {
InputStream is;
String type;
StreamGobbler(InputStream is, String type) {
this.is = is;
this.type = type;
}
public void run() {
try {
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line = null;
while ((line = br.readLine()) != null) {
if (type.equals("Error"))
LogManager.logError(line);
else
LogManager.logDebug(line);
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
TestPrint.bat:
echo P1=%1 >D:"2.1.2env"2.1.2home"CompuSet"output"TestPrint.log
echo P2=%2 >>D:"2.1.2env"2.1.2home"CompuSet"output"TestPrint.log
echo P3=%3 >>D:"2.1.2env"2.1.2home"CompuSet"output"TestPrint.log
echo P4=%4 >>D:"2.1.2env"2.1.2home"CompuSet"output"TestPrint.log
echo P5=%5 >>D:"2.1.2env"2.1.2home"CompuSet"output"TestPrint.log
echo P6=%6 >>D:"2.1.2env"2.1.2home"CompuSet"output"TestPrint.log
Bad_TestPrint.log:
P1=C:"xPression"CompuSet"output"MartyTestOut1.afp
P2=Literal1
P3="Rick Skinner"
P4=Parameter3
Good_TestPrint.log
P1=C:"xPression"CompuSet"output"MartyTestOut1.afp
P2=Literal1
P3="Rick Skinner"
P4=Parameter3
P5=Parameter4
P6=Parameter5
分享到:
相关推荐
它提供了线程的创建、启动、挂起、终止等方法。 - **常用属性**: - **ManagedThreadId**:每个线程都有一个唯一的标识符,通常用于识别线程。 - **Name**:虽然线程的名称不是必须的,但它有助于调试和日志记录...
本文将深入探讨Java的多线程机制,包括程序、进程和线程的区别,线程的生命周期,以及线程调度和优先级。 首先,程序是静态的代码,它定义了应用程序的行为,而进程是程序在执行过程中的实例,具有独立的内存空间。...
多线程还涉及到线程的状态管理,MFC提供了多个函数来管理线程的创建、挂起、恢复和终止,如CreateThread、SuspendThread、ResumeThread和ExitThread。 最后,要特别注意的是,MFC的多线程编程需要开发者对线程安全...
`SetThreadPriority`用于设置线程优先级,`SuspendThread`和`ResumeThread`分别用于挂起和恢复线程。线程间通信可以通过`PostThreadMessage`发送消息,或者使用线程安全的数据结构和同步对象,如`CSingleLock`、`...
CRT(C Runtime Library)提供了内存分配、文件操作等服务,并且Visual C++提供了CRT库的多线程版本,能够更好地支持多线程程序。 文档提到了一些函数,如_endthread和_endthreadex,这两个函数在Visual C++中用于...
使用`AfxBeginThread`函数可以创建用户界面线程,需要提供派生自CWinThread的类的RUNTIME_CLASS,以及其他可选参数如线程优先级、堆栈大小、创建状态(是否挂起)和安全属性。 **线程同步** 在多线程环境中,可能...
- 线程的状态:线程有多种状态,如新建、运行、挂起、停止等,可以通过IsAlive属性检查线程是否仍在运行。 - Thread 的方法:包括Start()启动线程,Join()等待线程结束,Abort()强制终止线程等。 - 开发实例:创建...
每个线程在执行特定操作前都会检查条件,如果条件不满足,线程会被挂起等待;当条件满足时,线程会被唤醒继续执行。 让我们详细解释一下`threading.Condition`的主要方法: 1. `__enter__()` 和 `__exit__()`:这...
- 线程管理包括线程的启动、挂起、恢复等操作,这些可以通过`SuspendThread`、`ResumeThread`等函数实现。 - 线程终止通常通过`TerminateThread`函数完成,但应谨慎使用,因为它可能导致数据不一致和其他问题。 2...
- 检查是否有线程被意外地挂起或等待。 - **1.3.6 多个锁导致的锁链分析** - 分析线程堆栈中的锁信息,找出可能存在的锁链顺序问题。 - 调整代码逻辑,尽可能减少锁的竞争。 - **1.3.7 通过线程堆栈进行性能瓶颈...
一个C#程序从由CLR(Common Language Runtime)和操作系统自动创建的单个线程(即“主”线程)开始,并通过创建额外的线程变为多线程程序。 以下是一个简单的示例及其输出: ```csharp using System; using System....
由于文档内容过长,这里将...以上知识点覆盖了Java面试中常见的问题,包括Java基础、集合框架、多线程、IO流、网络通信、异常处理、设计模式、Java Web技术以及JVM相关问题。掌握这些知识点对于通过Java面试至关重要。
本篇文档对后端开发中的关键知识点进行了全面而深入的梳理,涵盖了Java语言基础、JVM、操作系统、网络技术、数据库、缓存、多线程、Spring框架等方面的核心概念和技术要点。以下是针对文档标题、描述以及部分内容中...
Java虚拟机对于多线程是通过线程轮流切换并且分配线程执行时间的一个处理器只会处理执行一个线程,如果当前被执行的线程它所分配的执行时间用完了【挂起】。处理器会切换到另外的一个线程上来进行执行。程序计数器是...
与cgi的区别在于servlet处于服务器进程中,它通过多线程方式运行其service方法,一个实例可以服务于多个请求,并且其实例一般不会销毁,而CGI对每个请求都产生新的进程,服务完成后就销毁,所以效率上低于servlet。...
C#程序启动时会自动由CLR(Common Language Runtime)和操作系统创建一个主线程("main" thread),并通过创建额外的线程使其成为多线程程序。 #### 如何工作 多线程使程序能够同时执行多个任务。例如,一个应用程序...
- 进程和线程管理:创建、终止、挂起、恢复进程和线程。 - 系统信息获取:获取系统版本、硬件信息、内存状态等。 - 文件和注册表操作:读写文件、目录,访问和修改注册表键值。 - 窗口和控件操作:创建、移动、大小...
如果该锁已经被其他线程持有,正在执行的线程要么等待,要么挂起。 49. **死锁**:多个线程在执行过程中因争夺资源而造成的一种僵局。 50. **防止死锁的方法**:设置资源申请的顺序,限制线程对资源的最大占用,...