java如何中止阻塞进程。getInputStream()。用close()读取()吗?
我正试图中止一个已经阻塞的输入流。read()关闭流,但read()不会返回
public static void main(String args[]) throws Exception
{
ProcessBuilder builder = new ProcessBuilder("sleep", "100000");
Process process = builder.start();
final InputStream is = process.getInputStream();
Thread worker = new Thread() {
public void run() {
try {
int data;
while ((data = is.read()) != -1) {
System.out.println("Read:" + data);
}
} catch(IOException e) {
e.printStackTrace();
}
}
};
worker.start();
Thread.sleep(2000);
// process.destroy();
is.close();
worker.join();
}
是否有某种方法可以通过关闭流而不调用进程来中止已经阻塞的read()。销毁()
这个问题的背景是一个复杂的eclipse插件,它在大多数情况下都会中止阻塞的BufferedReader。readLine()调用进程。destroy(),但有时readLine()不会中止。我怀疑JVM内部ProcessReaper线程存在竞争,我正试图通过显式关闭流来解决这个问题
我正在使用Linux和JDK 1.7.0_25-b15
# 1 楼答案
你试过
close()
但没用。我唯一能想到的另一件事是在被阻止的线程上调用Thread.interrupt()
。。。但我怀疑这也行得通真正的问题是,规范(即各自的javadoc)没有说明这些东西是否有效。即使他们真的有用。。。对于某些操作系统平台上的Java版本。。。不能保证它们会在其他版本/平台组合上工作
# 2 楼答案
我想我不能在Java1.7中确定,但我在Java1.6中做到了这一点。你需要3个线程:
读取线程应该更新它和监视器线程之间共享的引用,但更重要的是,监视器需要有对读取线程的引用读取线程在每次读取时更新时间值。显示器在设定的时间内睡眠,每次醒来时,它都会检查时间戳。如果上一次和当前时间之间的差值超过某个值,监视器会强制读取线程中断,然后也会自动停止
可以想象,这只需要两个线程——主线程和监视器,其中主线程将进行读取并执行
monitor.setReaderThread(Thread.currentThread()); monitorThread.start()
。但我只用了三个线程# 3 楼答案
我有一个类似的问题,我通过在读取流之前检查大量可用字节来解决。 修改您的示例:
可以修改代码以中断工作线程,而不是使用布尔标志
我使用的是Windows 10和Oracle Java 8
# 4 楼答案
我看到过类似的情况,在我的例子中,每次java线程阻塞时,都是因为子进程将文件描述符提供给了它自己的子进程,在调用
Process.destroy()
后,该子进程仍处于活动状态。所以,示意图上是这样的:我确实检查了Windows和Linux平台的
Process.destroy()
源代码,结果执行了一个kill 9
命令。如果要杀死一个孙子,就需要一个kill -9
命令。我不知道在不使用JNI的情况下有什么好方法可以解决这个问题,但是既然您是为Eclipse编写的,那么您可以试试运气使用CDT Spawner类而不是java.lang.Runtime
。我记得它提供了一些运行时之外的功能,但不记得它是否能解决这个问题。例如,该类用于通过Eclipse CDT环境启动和调试本机进程BugJDK-4770092解释了为什么很难在Windows上杀死孙进程。据我所知,Sun/Oracle决定提供最低的公分母,这就是为什么在Unix上也没有孙辈被杀的原因
再想一想,如果我错了,那就去处理。destroy()发送一个SIGTERM,下面的shell脚本应该将所有子进程与java隔离,并且可以在Linux和Windows上的Cygwin中工作
# 5 楼答案
老问题,新答案。NuProcess库为进程实现非阻塞I/O,因此可以完全避免这种情况
免责声明:我是NuProcess的作者