记录一个用Runtime.getRuntime()执行java-jar的代码,解决不更新镜像更新容器内的jar包方法

文章讲述了在Java中使用Runtime.exec()执行命令时,必须在其他线程中处理Process的输出流和错误流,以避免阻塞主线程。同时,指出了读取输入流可能导致内存泄漏的问题,并提供了一个简单的读取优化方案,每500次读取后重置字节数组。另外,文章还提到了主方法中的Processexec执行和下载jar包的流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

两点:

  1. 一定要起其他线程处理Process exec = Runtime.getRuntime().exec(cmd); 执行完返回的Process的输出流和输出流。否则会导致主线程卡住

  1. Process的inputStream流,因为一直有访问根本不会为空,readInputStream方法里有写

主方法

    public static Boolean runJar() {
        try {
            //通过接口获取是否需要更新jar包
            //拿不到或者报错,都是走之前的jar包
            int status = 0;
            //拿到,判断下状态是否需要更新
            if (0 == status) {
                //需要更新,解析出URL
                String downLodePath = "downLodePath";
                String savePath = "savePath";
                String fileName = "fileName";
                //下载文件
                if (downLoadFromUrl(downLodePath, savePath, fileName)) {
                    //下载成功,执行 java -jar 方法
                    String cmd = "java -jar " + savePath + fileName + " &";
                    logger.info("cmd:{}",cmd);
                    Process exec = Runtime.getRuntime().exec(cmd);
                    logger.info("项目运行jar包命令方式启动完成");
                    InputStream inputStream = exec.getInputStream();
                    InputStream errStream = exec.getErrorStream();
                    Thread inputThread = new Thread(new InputStreamThread(inputStream));
                    inputThread.start();
                    Thread errThread = new Thread(new InputStreamThread(errStream));
                    errThread.start();
                    return true;
                }else{
                    logger.error("jar包下载失败,url:{}",downLodePath);
                    return false;
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            return false;
        }
        return false;
    }

主方法用到的方法

/**
     * 封装的通过URL下载包的方法
     */
    private static boolean downLoadFromUrl(String urlStr, String savePath, String fileName) {
        final HttpClient httpClient = HttpClient.newBuilder()
                .version(HttpClient.Version.HTTP_1_1)
                .connectTimeout(Duration.ofSeconds(50))
                .build();
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(urlStr))
                .header("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)")
                .build();
        final CompletableFuture<HttpResponse<Path>> httpResponseCompletableFuture = httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofFile(Path.of(savePath + fileName)));
        final HttpResponse<Path> join = httpResponseCompletableFuture.join();
        return HttpServletResponse.SC_OK == join.statusCode();
    }
    /**
     * 从输入流中获取字节数组
     */
    private static void readInputStream(InputStream inputStream) throws IOException {
        byte[] buffer = new byte[1024];
        int len = 0;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        int i=1;
        while((len = inputStream.read(buffer)) != -1) {
            /**
             * 这里是重点
             *
             * 因为inputStream流根本不会为空,所以这个while根本不会跳出去,因此ByteArrayOutputStream就会慢慢积累变得很大导致内存泄漏
             * 因此这里每500次重置一下
             */
            if(i>500){
                bos.close();
                bos = new ByteArrayOutputStream();
                i = 1;
            }
            bos.write(buffer, 0, len);
            logger.info(new String(buffer,0,len));
            i++ ;
        }
        bos.close();
        logger.info("while逻辑执行完毕!");
        return ;
    }

    private static class InputStreamThread implements Runnable{
        private InputStream inputStream;
        public InputStreamThread(InputStream stream){
            inputStream = stream;
        }
        public void run(){
            try {
                readInputStream(inputStream);
            }catch (Exception e){
                logger.error(e);
            }
        }
    }

待优化点

1、可以优化一下主方法里的 Process exec = Runtime.getRuntime().exec(cmd); 这块,因为用原生的Process时候,虽然打断点的时候可以去看执行的linux命令执行状态,但是如果直接在主方法里使用会报错。百度了只要重新就行,我用不到,所以没改。可以自行修改。

2、readInputStream 方法可以优化优化,当时为了解决问题就很潦草。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值