zoukankan      html  css  js  c++  java
  • Process.waitFor() 死锁问题了解和解决

    ProcessBuilder pb = new ProcessBuilder("C:\Debug\TestRedis.exe", keyNmae);
    pb.redirectErrorStream(true);
    Process process = pb.start();
    //可能导致进程阻塞,甚至死锁
    int ret = process.waitFor();

    1、waitFor问题描述分析

    1、 主进程中调用pb.start会创建一个子进程,用于执行shell /exe 脚本。子进程创建后会和主进程分别独立运行。
    2.、因为主进程需要等待脚本执行完成,然后对脚本返回值或输出进行处理,所以这里主进程调用process.waitFor()等待子进程完成。

    3.、进程执行过程就是不断的打印信息。主进程中可以通过Process.getInputStream和Process.getErrorStream获取并处理。
    4.、这时候子进程不断向主进程发生数据,而主进程调用Process.waitfor后已挂起。当前子进程和主进程之间的缓冲区塞满后进程不能继续写数据,然后也会挂起
    5.、这样子进程等待主进程读取数据,主进程等待子进程结束,两个进程相互等待,最终导致死锁。

    2、解决死锁问题

    基于上述分析,只要主进程在waitFor之前,能不断处理缓冲区中的数据就可以。因为,我们可以再waitfor之前,单独启2个额外的线程,分别用于处理InputStream和ErrorStream就可以

                    try (
                            InputStream inputStream = process.getInputStream();
                            InputStream inputErrorStream = process.getErrorStream();
                    ) {
                        // 读取Shell的输出内容,并添加到string中:
                        //启动两个线程,一个线程负责读标准输出流,另一个负责读标准错误流
                        new Thread(() -> {
                            try {
                                val msg = IOUtils.toString(inputStream, StandardCharsets.UTF_8);
                                response.setShellOutput(msg);
                            } catch (Exception e) {
                                log.error(e.getMessage(), e);
                            }
                        }).start();
    
                        new Thread(() -> {
                            try {
                                var errMsg = IOUtils.toString(inputErrorStream, StandardCharsets.UTF_8);
                                response.setShellErrorOutput(errMsg);
                            } catch (Exception e) {
                                log.error(e.getMessage(), e);
                            }
                        }).start();
    
                        process.waitFor(2, TimeUnit.HOURS);////可能导致进程阻塞,甚至死锁
                        int exitCode = process.exitValue();//
                        response.setSuccessful(exitCode == SHELL_EXIT_CODE_SUCCESS);
                    }
  • 相关阅读:
    设置linux查看历史命令显示执行时间
    CentOS7.6操作系统安装实例以及Linux版本、哲学思想介绍
    JavaScript 数据结构1
    原生js 正则表达
    js Event事件
    引用类型: 归并方法
    引用类型: 迭代方法
    引用类型 位置方法 indexOf()和 lastIndexOf()
    引用类型 操作方法
    引用类型 重排序方法
  • 原文地址:https://www.cnblogs.com/muzhongjiang/p/13390606.html
Copyright © 2011-2022 走看看