java 阻止 运行 shell 命令使用进程
java block while run shell command using process
我有一个 Java 项目可以帮助使用 youtube-dl 在 youtube 播放列表中查找所有视频信息。这是 Main.java
import java.io.*;
public class Main {
public static void main(String[] args) throws Exception {
String command1 = "/usr/local/bin/youtube-dl --flat-playlist --dump-single-json https://www.youtube.com/playlist?list=PLFcOH1YaRqUo1yEjY5ly09RFbIpUePF7G";
String command2 = "/usr/local/bin/youtube-dl --flat-playlist --dump-single-json https://www.youtube.com/playlist?list=PLC6A0625DCA9AAE2D";
System.out.println(executeCommand(command1));
}
private static String executeCommand(String command) throws IOException, InterruptedException {
int exitCode = 0;
String result = "";
Process process;
ProcessBuilder builder = new ProcessBuilder(command.replaceAll("[ ]+", " ").split(" "));
builder.directory(new File("/tmp/test"));
process = builder.start();
exitCode = process.waitFor();
return getStringFromInputStream(process.getInputStream());
}
private static String getStringFromInputStream(InputStream is) {
BufferedReader br = null;
StringBuilder sb = new StringBuilder();
String line;
try {
br = new BufferedReader(new InputStreamReader(is));
while ((line = br.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return sb.toString();
}
}
command1
和 command2
除了 Youbute 播放列表参数外完全相同。 command2
中的播放列表有 409 个视频,command1
中有 200 个视频。我可以在终端中成功获得这两个命令的结果。只是 command2
需要更多时间,但只有几秒钟。但是当我 运行 Main.java
(javac Main.java; java Main) 时,对于 command1
它打印结果成功,但是对于 command2
它挂在那里几分钟没有任何结果。这是此过程的 jstack
"main" #1 prio=5 os_prio=0 tid=0x00007f828c009800 nid=0xce7 in Object.wait() [0x00007f8293cf7000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x0000000771df9fe0> (a java.lang.UNIXProcess)
at java.lang.Object.wait(Object.java:502)
at java.lang.UNIXProcess.waitFor(UNIXProcess.java:396)
- locked <0x0000000771df9fe0> (a java.lang.UNIXProcess)
at Main.executeCommand(Main.java:18)
at Main.main(Main.java:8)
它挂在 exitCode = process.waitFor();
。我对此一无所知。谁能帮我?非常感谢。
如评论中所述,默认情况下子进程的输出被发送到可以使用 Process.getInputStream() 读取的管道。如果子进程生成大量输出并且 Java 程序不使用它,管道的缓冲区将填满并且子进程将在写入时阻塞。
最简单的解决方案是在 ProcessBuilder 上调用 .inheritIO()。这会将输出发送到控制台,而不是将其缓冲在内存中(输入和错误流也是如此)。
我有一个 Java 项目可以帮助使用 youtube-dl 在 youtube 播放列表中查找所有视频信息。这是 Main.java
import java.io.*;
public class Main {
public static void main(String[] args) throws Exception {
String command1 = "/usr/local/bin/youtube-dl --flat-playlist --dump-single-json https://www.youtube.com/playlist?list=PLFcOH1YaRqUo1yEjY5ly09RFbIpUePF7G";
String command2 = "/usr/local/bin/youtube-dl --flat-playlist --dump-single-json https://www.youtube.com/playlist?list=PLC6A0625DCA9AAE2D";
System.out.println(executeCommand(command1));
}
private static String executeCommand(String command) throws IOException, InterruptedException {
int exitCode = 0;
String result = "";
Process process;
ProcessBuilder builder = new ProcessBuilder(command.replaceAll("[ ]+", " ").split(" "));
builder.directory(new File("/tmp/test"));
process = builder.start();
exitCode = process.waitFor();
return getStringFromInputStream(process.getInputStream());
}
private static String getStringFromInputStream(InputStream is) {
BufferedReader br = null;
StringBuilder sb = new StringBuilder();
String line;
try {
br = new BufferedReader(new InputStreamReader(is));
while ((line = br.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return sb.toString();
}
}
command1
和 command2
除了 Youbute 播放列表参数外完全相同。 command2
中的播放列表有 409 个视频,command1
中有 200 个视频。我可以在终端中成功获得这两个命令的结果。只是 command2
需要更多时间,但只有几秒钟。但是当我 运行 Main.java
(javac Main.java; java Main) 时,对于 command1
它打印结果成功,但是对于 command2
它挂在那里几分钟没有任何结果。这是此过程的 jstack
"main" #1 prio=5 os_prio=0 tid=0x00007f828c009800 nid=0xce7 in Object.wait() [0x00007f8293cf7000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x0000000771df9fe0> (a java.lang.UNIXProcess)
at java.lang.Object.wait(Object.java:502)
at java.lang.UNIXProcess.waitFor(UNIXProcess.java:396)
- locked <0x0000000771df9fe0> (a java.lang.UNIXProcess)
at Main.executeCommand(Main.java:18)
at Main.main(Main.java:8)
它挂在 exitCode = process.waitFor();
。我对此一无所知。谁能帮我?非常感谢。
如评论中所述,默认情况下子进程的输出被发送到可以使用 Process.getInputStream() 读取的管道。如果子进程生成大量输出并且 Java 程序不使用它,管道的缓冲区将填满并且子进程将在写入时阻塞。
最简单的解决方案是在 ProcessBuilder 上调用 .inheritIO()。这会将输出发送到控制台,而不是将其缓冲在内存中(输入和错误流也是如此)。