zoukankan      html  css  js  c++  java
  • Java中RunTime类介绍

    Runtime 类代表着Java程序的运行时环境,每个Java程序都有一个Runtime实例,该类会被自动创建,我们可以通过Runtime.getRuntime() 方法来获取当前程序的Runtime实例。

    获取当前Jvm的内存信息

    /*
     * 获取当前jvm的内存信息,返回的值是 字节为单位
     * */
    public static void getFreeMemory() {
        //获取可用内存
        long value = Runtime.getRuntime().freeMemory();
        System.out.println("可用内存为:"+value/1024/1024+"mb");
        //获取jvm的总数量,该值会不断的变化
        long  totalMemory = Runtime.getRuntime().totalMemory();
        System.out.println("全部内存为:"+totalMemory/1024/1024+"mb");
        //获取jvm 可以最大使用的内存数量,如果没有被限制 返回 Long.MAX_VALUE;
        long maxMemory = Runtime.getRuntime().maxMemory();
        System.out.println("可用最大内存为:"+maxMemory/1024/1024+"mb");
    }

    获取jvm可用的处理器核心的数量

    一般可以和newFixedThreadPool一起使用

    /*
     * 获取jvm可用的处理器核心的数量
     * */
    public static void getAvailableProcessors() {
        int value = Runtime.getRuntime().availableProcessors();
        System.out.println(value);
       ExecutorService fixedThreadPool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());  }

    执行系统命令

    RunTime.getRuntime().exec()的构造方法

    public Process exec(String command)-----在单独的进程中执行指定的字符串命令。
    public Process exec(String [] cmdArray)---在单独的进程中执行指定命令和变量
    public Process exec(String command, String [] envp)----在指定环境的独立进程中执行指定命令和变量
    public Process exec(String [] cmdArray, String [] envp)----在指定环境的独立进程中执行指定的命令和变量
    public Process exec(String command,String[] envp,File dir)----在有指定环境和工作目录的独立进程中执行指定的字符串命令
    public Process exec(String[] cmdarray,String[] envp,File dir)----在指定环境和工作目录的独立进程中执行指定的命令和变量

     Process的几种方法

    1.destroy():杀掉子进程
    2.exitValue():返回子进程的出口值,值 0 表示正常终止
    3.getErrorStream():获取子进程的错误流
    4.getInputStream():获取子进程的输入流
    5.getOutputStream():获取子进程的输出流
    6.waitFor():导致当前线程等待,如有必要,一直要等到由该Process对象表示的进程已经终止。如果已终止该子进程,此方法立即返回。如果没有终止该子进程,调用的线程将被阻塞,直到退出子进程,根据惯例,0 表示正常终止

    注意:在java中,调用runtime线程执行脚本是非常消耗资源的,所以切忌不要频繁使用!

    在调用runtime去执行脚本的时候,其实就是JVM开了一个子线程去调用JVM所在系统的命令,其中开了三个通道:输入流、输出流、错误流,其中输出流就是子线程走调用的通道。
    大家都知道,waitFor是等待子线程执行命令结束后才执行, 但是在runtime中,打开程序的命令如果不关闭,就不算子线程结束。比如以下代码。

    private static Process p = null;
    p = Runtime.getRuntime().exec("notepad.exe");
    p.waitFor();         
    System.out.println("-------------------我被执行了-------------------");

    以上代码中,打开windows中记事本。如果我们不手动关闭记事本,那么输出语句就不会被执行,这点是需要理解的。  

    process的阻塞

    在runtime执行大点的命令中,输入流和错误流会不断有流进入存储在JVM的缓冲区中,如果缓冲区的流不被读取被填满时,就会造成runtime的阻塞。所以在进行比如:大文件复制等的操作时,我们还需要不断的去读取JVM中的缓冲区的流,来防止Runtime的死锁阻塞。
        
    代码:linux中拷贝文件防止阻塞的写法

    打开记事本

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

    打开某个文件(不管是word还excel等等文件)

    Runtime.getRuntime().exec("cmd /c start " + """ "" + path + """);

    打开ie浏览器

    Runtime.getRuntime().exec("C:\Program Files\Internet Explorer\IEXPLORE.EXE");

    得到系统的环境变量

    @Test
    public void dirRuntimeProcess() throws IOException, InterruptedException {
        Process process = Runtime.getRuntime().exec("cmd.exe /c echo %JAVA_HOME%");
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
    
        String string = null;
        while ((string = bufferedReader.readLine()) != null) {
            System.out.println(string); // D:Javajdkjdk1.8.0_152
        }
        process.waitFor();
        System.out.println("return: " + process.exitValue()); // return: 0
    }

    得到java的版本号,这个和上述的不一样

    @Test
    public void getJavaVersion() {
        try {
            Process process = Runtime.getRuntime().exec("javac -version");
            BufferedReader br = new BufferedReader(new InputStreamReader(process.getErrorStream()));
            String line = null;
            while ((line = br.readLine()) != null)
                System.out.println(line); // javac 1.8.0_152
            process.waitFor();
            System.out.println("Process exitValue: " + process.exitValue());
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }

    执行外部命令得到的结果

    @Test
    public void execProgramC() {
        try {
            Process process = Runtime.getRuntime().exec("C:/Users/76801/Desktop/huhx.exe");
            BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line = null;
            while ((line = br.readLine()) != null)
                System.out.println(line); // Hello World.
            process.waitFor();
            System.out.println("Process exitValue: " + process.exitValue());
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }

    huhx.c比较简单,就是打印一句话。

    #include<stdio.h>
    
    void main() {
        printf("Hello World.");
    }

    导出mysql脚本

    @Test
    public void execMysqldump() throws IOException, InterruptedException {
        String execCommand = "cmd c/ D:/Java/mysqldump.exe -uhuhx -phuhx boot_learn > D:/bootlearn.sql";
        System.out.println("exec command: " + execCommand);
        Runtime runtime = Runtime.getRuntime();
        Process p = runtime.exec(execCommand);
        StreamGobbler errorGobbler = new StreamGobbler(p.getErrorStream(), "Error");
        StreamGobbler outputGobbler = new StreamGobbler(p.getInputStream(), "Output");
        errorGobbler.start();
        outputGobbler.start();
        p.waitFor();
        System.out.println("successful." + p.exitValue());
    }

    上述也使用到了网上所说的读出窗口的标准输出缓冲区中的内容,仍旧没有解决Process的waitFor阻塞问题。下面是清空缓冲区的线程代码:

    public class StreamGobbler extends Thread {
    
        InputStream is;
        String type;
    
        public StreamGobbler(InputStream is, String type) {
            this.is = is;
            this.type = type;
        }
    
        public void run() {
            try (InputStreamReader isr = new InputStreamReader(is);) {
                BufferedReader br = new BufferedReader(isr);
                String line = null;
                while ((line = br.readLine()) != null) {
                    if (type.equals("Error")) {
                        System.out.println("Error   :" + line);
                    } else {
                        System.out.println("Debug:" + line);
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    代码的目标是导出mysql数据库的脚本。没有找到问题的解决方案,运行环境是win10,jdk1.8。

    在JVM中增加一个关闭的钩子

    阅读ElasticSearch的源码时,BootStrap类中调用了Runtime.getRuntime().addShutdownHook方法。接下来对java.lang包中的Runtime类的addShutdownHook方法进行说明。

    这个方法的意思就是在JVM中增加一个关闭的钩子,当JVM关闭的时候,会执行系统中已经设置的所有通过方法addShutdownHook添加的钩子,当系统执行完这些钩子后,JVM才会关闭。所以这些钩子可以在JVM关闭的时候进行内存清理、对象销毁等操作。

    为了更清晰的说明,编写如下程序:

    public class TestShutdownHook {
        public static void main(String[] args) {
            // thread1
            Thread thread1 = new Thread() {
                public void run() {
                    System.out.println("thread1");
                }
            };
     
            // thread2
            Thread thread2 = new Thread() {
                public void run() {
                    System.out.println("thread2");
                }
            };
     
            // shutdownThread
            Thread shutdownThread = new Thread() {
                public void run() {
                    System.out.println("shutdownThread");
                }
            };
     
            Runtime.getRuntime().addShutdownHook(shutdownThread);
     
            thread1.start();
            thread2.start();
        }
    }

    输出结果:

    thread1
    thread2
    shutdownThread
    或
    thread2
    thread1
    shutdownThread

    无论是先打印thread1还是thread2,shutdownThread 线程都是最后执行的(因为这个线程是在JVM执行关闭前才会执行)。

    关闭JVM程序

    Runtime的exit表示的关闭JVM程序,但是不释放内存,举例:

    System.exit(0);//表示正常程序的关闭,执行的是以下操作:
    public static void exit(int status) {
        Runtime.getRuntime().exit(status);
    }

    备注:如果是 0表示正常关闭,如果是非0表示异常关闭,如果想释放内存的话,用“dispose()”关闭当前程序,并释放资源。

    System.exit()的内部实现也是Runtime.getRuntime().exit();

  • 相关阅读:
    电机驱动MCU通用功能和技术点解析
    串行SPI NOR闪存VS并行NOR闪存
    非易失性存储器Flash和EEPROM之间的差异与优缺点
    为何要使用MCU
    MRAM实现对车载MCU中嵌入式存储器的取代
    ​弥补现有MRAM的不足
    将赛普拉斯nvSRAM替换为MRAM
    PSRAM在数据缓冲应用中可以取代SRAM或SDRAM
    数据库建表语句备份(二)
    数据库建表语句备份(一)
  • 原文地址:https://www.cnblogs.com/shamo89/p/9807019.html
Copyright © 2011-2022 走看看