java中运行指令浅析

java,运行,指令,浅析 · 浏览次数 : 37

小编点评

**1. 使用 `Runtime.getRuntime().exec()` 执行指令** 在 `Windows` 和 `Linux` 平台上,`Runtime.getRuntime().exec()` 函数的使用方法相同。但是,在 `Windows` 中,`exec()` 函数返回的 `Process` 对象可能与实际执行的进程不同,因为它可能指向系统进程。 **2. 获取返回值** 在 `Windows` 和 `Linux` 平台上,可以使用 `BufferedReader` 或 `InputStreamReader` 读取进程的输出内容。`BufferedReader` 使用 `readLine()` 方法读取一行文本,而 `InputStreamReader` 使用 `read()` 方法读取全部输入内容。 **3. 模拟结果缓存** 为了减少重复执行相同的指令的成本,可以使用缓存机制。可以在每次执行 `exec()` 后,将输出内容缓存到全局数组中。这样可以避免再次执行相同的指令。 **4. 进程所属关系** 在 `Java` 中,使用 `ThreadUtil` 的 `execAsync()` 方法可以执行异步执行,并设置线程所属关系。这可以让当程序停止运行时,其子线程也会被停止。 **5. 示例代码** 以下示例展示了如何在 `Windows` 和 `Linux` 平台上执行 `notepad` 指令并获取返回值的代码: ```java import java.io.BufferedReader; import java.io.InputStreamReader; public class NotepadExample { public static void main(String[] args) throws Exception { String command = "notepad"; // 获取进程输出内容 StringBuilder sb = new StringBuilder(); Process process = Runtime.getRuntime().exec(command); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream())); String line; while ((line = bufferedReader.readLine()) != null) { sb.append(line).append("\n"); } bufferedReader.close(); // 打印输出内容 System.out.println(sb.toString()); } } ``` **6. 总结** 在 `Windows` 和 `Linux` 平台上,使用 `Runtime.getRuntime().exec()` 执行指令并获取返回值的方法相同。但是,在 `Windows` 中,`exec()` 函数返回的 `Process` 对象可能与实际执行的进程不同,因此需要设置线程所属关系。

正文

后续业务可能需要在程序中运行指令, 所以这里简单探究了一下, 分别从win和linux两个平台进行研究, 又以为java是跨平台语言, 可能二者之间的区别应该只是返回内容与输入指令的不同. (还不是在win上开发)

1. 如何使用

  • Runtime.getRuntime().exec("notepad");

  • RuntimeUtil.exec("notepad"); // hutool

    了解了使用方法, 接下来探究几个问题.

2. 如何获取返回值

  • 参考: java执行cmd命令并获取返回结果字符串

    public static String execCMD(String command) {
        StringBuilder sb = new StringBuilder();
        try {
            Process process = Runtime.getRuntime().exec(command);
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                sb.append(line).append("\n");
            }
        } catch (Exception e) {
            return e.toString();
        }
        return sb.toString();
    }
    
  • hutool中用法1: String str = RuntimeUtil.execForStr("ipconfig");

  • hutool中用法2: List<String> ss = RuntimeUtil.execForLines("ipconfig");

    需要注意一点:

    参数command: a string array containing the program and its arguments.

    以上所有的command 并不是cmd命令行中的命令, 而是在运行窗口(win+r)可以运行的, 比如dir这个典型的cmd命令, 在win+r的运行窗口就不能运行. 可以使用cmd /c dir 来运行.

    /c 是运行完不显示窗口, /k是运行完显示, 其他参数可在cmd指令中打出 cmd /? 查看

3. 模拟在取结果时候堵塞进程

  • 代码

    System.err.println(DateUtil.format(new Date(), DatePattern.NORM_DATETIME_MS_PATTERN));
    System.err.println(RuntimeUtil.execForStr("ping 192.168.0.222 /n 2"));
    System.err.println(DateUtil.format(new Date(), DatePattern.NORM_DATETIME_MS_PATTERN));
    
  • 输出:

    2022-07-15 16:34:50.523
    
    正在 Ping 192.168.0.222 具有 32 字节的数据:
    来自 192.168.0.222 的回复: 字节=32 时间=49ms TTL=128
    来自 192.168.0.222 的回复: 字节=32 时间=16ms TTL=128
    
    192.168.0.222 的 Ping 统计信息:
        数据包: 已发送 = 2,已接收 = 2,丢失 = 0 (0% 丢失),
    往返行程的估计时间(以毫秒为单位):
        最短 = 16ms,最长 = 49ms,平均 = 32ms
    
    2022-07-15 16:34:51.575
    
  • 结论

    确实可以看到两个时间相差1s左右. 可以将 ping ** /n 2中的2调大一些查看区别.

    接下来我们把ping命令换成notepadcmd /c notepad, 可以看到直接堵死了.

    在linux系统的终端运行firefox, 在终端会显示对应日志.

    对应到我们例子中, 执行exec方法时候会有返回一个进程p,

    我们就是从进程p的输入流中拿到的程序/指令返回的内容(写在命令行中的内容)

    正常情况下程序执行完就自动结束了, 但是记事本/firefox不会自动停止,

    所以线程会一直占用着, 与是否写日志无关.

    如果这种情况下获取返回内容, 可以将返回内容写入全局数组

    另外使用线程异步进行读取.

4. 刨析进程的从属关系

  • 代码(放在接口中测试)

    ThreadUtil.execAsync(() -> 
            RuntimeUtil.execForStr("notepad"));
    ThreadUtil.execAsync(() -> 
            RuntimeUtil.execForStr("ping 192.168.0.222 /t"));
    ThreadUtil.execAsync(() -> 
            RuntimeUtil.execForStr("notepad"));
    
  • 运行, 使用Process Explorer软件查看

    image

    运行一次.

    image

    运行3次.

    可以看到执行的这些都是java.exe的子线程, 那么当我们停止java.exe程序时候, 其下的子程序也会一起被杀掉吗?

    其实不会, 这些线程会被移动到根目录下

    image

    这很疑惑, 接下来来一个对比类型, 打开命令行输入`ping localhost \t, 查看进程

    image

    可以看到cmd是在explorer.exe下的进程, 就是我们的资源管理器(包括桌面这些, 并不只是我的电脑),

    而且不同之处是ping.exe, 代码生成的会自带一个conhost, 手动执行的则平级生成的.

    然后又测试了使用Runtime.getRuntime().exec("ping 192.168.0.111 /t");生成, 发现当关闭java.exe时还是会移动到最后.

    image

    手动杀掉java也不会影响(树影响), 但是手动命令行中启动的ping在只杀掉命令行时候会一同将子目录杀掉


    尚未在实际中应用, 暂时到此为止.

与java中运行指令浅析相似的内容:

java中运行指令浅析

后续业务可能需要在程序中运行指令, 所以这里简单探究了一下, 分别从win和linux两个平台进行研究, 又以为java是跨平台语言, 可能二者之间的区别应该只是返回内容与输入指令的不同. (还不是在win上开发) ## 1. 如何使用 - `Runtime.getRuntime().exec("n

十大java应用服务器(web server)总结

java应用服务器(web server),是指运行java程序的web应用服务器软件,不包括nginx、Apache等通用web服务器软件。 一、Tomcat Tomcat是Apache 软件基金会的Jakarta 项目中的一个核心项目,由Apache、Sun 和其他一些公司及个人共同开发而成。随

[转帖]SPECjvm测试工具详解

ARM服务器测试大纲中指定了要使用specjvm测试Java虚拟机性能,所以就上网找开源的测试套。 简介 SPECjvm2008(java虚拟机基准测试)是用来测试java运行环境(JRE)性能的基准测试套件,其中包含几个核心的JAVA功能实现的基准测试程序。该测试套测试了处理器和内存子系统的性能,

玩转服务器之环境篇:PHP和Python环境部署指南

前几篇文章中讲解了如何搭建docker和Java Web环境的方法,本篇文章来教大家搭建一个好的PHP和Python环境,可以帮助开发和运行PHP和Python应用程序,使其更加高效和稳定。 一、 PHP环境介绍 好的开发环境无疑会大大提升编码效率,近日钻研了一下Python环境安装的问题,稍加总结

[转帖]JVM类加载机制

概述 虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验,转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Cl

[转帖]讨论在 Linux Control Groups 中运行 Java 应用程序的暂停问题原创

https://heapdump.cn/article/1930426 说明 本篇原文来自 LinkedIn 的 Zhenyun Zhuang,原文:Application Pauses When Running JVM Inside Linux Control Groups[1],在容器化的进程中

Java -jar 运行 报 MalformedInputException: Input length = 1

Intellij IDEA 中运行正常,linux 运行正常, cmd 下运行 报:MalformedInputException: Input length = 1 微服务项目,在Nacos中做了配置,在引用 Nacos中配置时,编码问题,导致的错误 org.yaml.snakeyaml.erro

[转帖]Java系列 | Linux系统中运行JMeter脚本

https://www.cnblogs.com/tinywan/p/16243391.html 需求场景 在Windows环境下测试,并发数过大,整个主机直接崩掉 依赖说明 在Linux系统中运行JMeter脚本,需要有两个前提 1、Linux系统中配置好Java环境 2、Linux系统中配置好JM

Java中可以用的大数据推荐算法

在Java中实现大数据推荐算法时,通常会使用一些开源的机器学习库,如Apache Mahout、Weka、DL4J(DeepLearning4j,用于深度学习)或者Spark MLlib(用于在Spark集群上运行)。由于完整实现一个大数据推荐算法的代码量可能非常大,并且需要配合具体的数据集和环境进

关于对于Java中Entity以及VO,以及DTO中Request对象序列化的学习

关于 Serializable的探讨 前提引入 是由于软件测试上有同学提到说,什么该字段在程序刚运行时,导致jvm激增,所以吸引了我的注意 回顾代码 MybatisPlus Generator自动生成的entity中就经常带有这个, 而且我在开发代码的时候VO,以及DTO常常是直接复制对应的enti