首页 > 解决方案 > Java Unix 脚本执行线程休眠行为

问题描述

我有一个 java web-app 应用程序,它使用 ProcessBuilder 执行本机 unix bash 脚本,我的 unix 脚本在外部资源上有等待和睡眠逻辑。

在某些情况下,应用程序会间歇性挂起,我怀疑 unix 脚本执行可能是其背后的原因之一。

Java 代码示例:

public static void resourceCheck(String arg) throws IOException, InterruptedException {
    String[] cmd = { "sh", "/usr/hdf/current/nifi/custom_scripts/resExec.sh",arg};
    Process p = Runtime.getRuntime().exec(cmd);
    p.waitFor();
    BufferedReader reader=new BufferedReader(new InputStreamReader(
            p.getInputStream()));
   //Get results and log
}

Bash 脚本片段

while [ ! -f ${watcher_file} ]
do
    echo -e `date "+%Y-%m-%d %H:%M:%S"`" : Watcher file ${watcher_file} not created yet.\nWaiting for ${wait_timer} seconds" | tee -a "${LOG_FILE}"
    sleep ${wait_timer}
done

根据我的经验,我有大量的 java Thread.sleep 而不会影响应用程序,但我不确定 unix 脚本有线程睡眠会发生什么。

您能否解释一下当 Java Process builder 触发具有线程睡眠的 unix 脚本以及这种方法的任何潜在问题时它是如何工作的?

标签: javamultithreading

解决方案


您必须在waitFor读取过程标准输出流之后使用,而不是之前。如果您的应用程序没有正确使用 STDOUT / STDERR 流, Javaexec调用也可能会挂起,尽管它不清楚您的子进程是否写了很多。如果您切换到 ProcessBuilder 并将 STDERR 合并到 STDOUT ,则更容易解决此问题:

ProcessBuilder pb = new ProcessBuilder(cmd);
pb.redirectErrorStream(true);
Process p = pb.start();
try(var stdout = p.getInputStream()) {
   stdout.transferTo(System.out);  // or wherever
}
int rc = p.waitFor();

在某些 web 应用程序中使用这种类型的调用(即在调用线程中休眠的东西)不是一个好主意 - 例如,如果这是由 servlet 请求触发并且有多个客户端,您最终可能会收到所有请求在所有线程都在进行基本相同的等待时阻塞 Web 应用程序服务器 - 并且没有线程来处理新连接。


推荐阅读