最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用Runtime 調(diào)用Process.waitfor導(dǎo)致的阻塞問題

 更新時間:2021年12月14日 10:00:28   作者:弦上的夢  
這篇文章主要介紹了使用Runtime 調(diào)用Process.waitfor導(dǎo)致的阻塞問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

1. 關(guān)于Runtime類的小知識

  • Runtime.getRuntime()可以取得當(dāng)前JVM的運(yùn)行時環(huán)境,這也是在Java中唯一一個得到運(yùn)行時環(huán)境的方法
  • Runtime中的exit方法是退出JVM

2. Runtime的幾個重要的重載方法

方法名 作用
exec(String command); 在單獨(dú)的進(jìn)程中執(zhí)行指定的字符串命令。
exec(String command, String[] envp) 在指定環(huán)境的單獨(dú)進(jìn)程中執(zhí)行指定的字符串命令。
exec(String[] cmdarray, String[] envp, File dir) 在指定環(huán)境和工作目錄的獨(dú)立進(jìn)程中執(zhí)行指定的命令和變量
exec(String command, String[] envp, File dir) 在有指定環(huán)境和工作目錄的獨(dú)立進(jìn)程中執(zhí)行指定的字符串命令。

Runtime類的重要的方法還有很多,簡單列舉幾個

  • exit(int status):終止當(dāng)前正在運(yùn)行的 Java 虛擬機(jī)
  • freeMemory():返回 Java 虛擬機(jī)中的空閑內(nèi)存量。
  • load(String filename): 加載作為動態(tài)庫的指定文件名。
  • loadLibrary(String libname): 加載具有指定庫名的動態(tài)庫。

3. Runtime的使用方式

錯誤的使用exitValue()

  public static void main(String[] args) throws IOException {
        String command = "ping www.baidu.com";
        Process process = Runtime.getRuntime().exec(command);
        int i = process.exitValue();
        System.out.println("字進(jìn)程退出值:"+i);
    }

輸出:

Exception in thread "main" java.lang.IllegalThreadStateException: process has not exited
at java.lang.ProcessImpl.exitValue(ProcessImpl.java:443)
at com.lirong.think.runtime.ProcessUtils.main(ProcessUtils.java:26)

原因:

exitValue()方法是非阻塞的,在調(diào)用這個方法時cmd命令并沒有返回所以引起異常。阻塞形式的方法是waitFor,它會一直等待外部命令執(zhí)行完畢,然后返回執(zhí)行的結(jié)果。

修改后的版本:

  public static void main(String[] args) throws IOException {
        String command = "javac";
        Process process = Runtime.getRuntime().exec(command);
        process.waitFor();
        process.destroy();
        int i = process.exitValue();
        System.out.println("字進(jìn)程退出值:"+i);
    }

此版本已然可以正常運(yùn)行,但當(dāng)主線程和子線程有很多交互的時候還是會出問題,會出現(xiàn)卡死的情況。

4. 卡死原因

  • 主進(jìn)程中調(diào)用Runtime.exec會創(chuàng)建一個子進(jìn)程,用于執(zhí)行cmd命令。子進(jìn)程創(chuàng)建后會和主進(jìn)程分別獨(dú)立運(yùn)行。
  • 因為主進(jìn)程需要等待腳本執(zhí)行完成,然后對命令返回值或輸出進(jìn)行處理,所以這里主進(jìn)程調(diào)用Process.waitfor等待子進(jìn)程完成。
  • 運(yùn)行此cmd命令可以知道:子進(jìn)程執(zhí)行過程就是打印信息。主進(jìn)程中可以通過Process.getInputStream和Process.getErrorStream獲取并處理。
  • 這時候子進(jìn)程不斷向主進(jìn)程發(fā)生數(shù)據(jù),而主進(jìn)程調(diào)用Process.waitfor后已掛起。當(dāng)前子進(jìn)程和主進(jìn)程之間的緩沖區(qū)塞滿后,子進(jìn)程不能繼續(xù)寫數(shù)據(jù),然后也會掛起。
  • 這樣子進(jìn)程等待主進(jìn)程讀取數(shù)據(jù),主進(jìn)程等待子進(jìn)程結(jié)束,兩個進(jìn)程相互等待,最終導(dǎo)致死鎖。

5. 解決方案

不斷的讀取消耗緩沖區(qū)的數(shù)據(jù),以至子進(jìn)程不會掛起,下面是具體代碼:

/**
 * @author lirong
 * @desc CMD命令測試
 * @date 2019/06/13 20:50
 */
@Slf4j
public class ProcessUtils {
    public static void main(String[] args) throws IOException, InterruptedException {
        String command = "ping www.baidu.com";
        Process process = Runtime.getRuntime().exec(command);
        readStreamInfo(process.getInputStream(), process.getErrorStream());
        int exit = process.waitFor();
        process.destroy();
        if (exit == 0) {
            log.debug("子進(jìn)程正常完成");
        } else {
            log.debug("子進(jìn)程異常結(jié)束");
        }
    }
    /**
     * 讀取RunTime.exec運(yùn)行子進(jìn)程的輸入流 和 異常流
     * @param inputStreams 輸入流
     */
    public static void readStreamInfo(InputStream... inputStreams){
        ExecutorService executorService = Executors.newFixedThreadPool(inputStreams.length);
        for (InputStream in : inputStreams) {
            executorService.execute(new MyThread (in));
        }
        executorService.shutdown();
    }
}
/**
 * @author lirong
 * @desc
 * @date 2019/06/13 21:25
 */
@Slf4j
public class MyThread implements Runnable {
    private InputStream in;
    public MyThread(InputStream in){
        this.in = in;
    }
    @Override
    public void run() {
        try{
            BufferedReader br = new BufferedReader(new InputStreamReader(in, "GBK"));
            String line = null;
            while((line = br.readLine())!=null){
                log.debug(" inputStream: " + line);
            }
        }catch (IOException e){
            e.printStackTrace();
        }finally {
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

寫到這里大家以為都結(jié)束了哇,并沒有,哈哈哈,真實(shí)的生成環(huán)境總能給你帶來很多神奇的問題,Runtime不僅可以直接調(diào)用CMD執(zhí)行命令,還可以調(diào)用其他.exe程序執(zhí)行命令。

所以縱使你讀取了緩沖區(qū)的數(shù)據(jù),你的程序依然可能會被卡死,因為有可能你的緩沖區(qū)根本就沒有數(shù)據(jù),而是你的.exe程序卡主了。嗯,所以為你以防萬一,你還需要設(shè)置超時。

6. Runtime最優(yōu)雅的調(diào)用方式

/**
 * @author lirong
 * @desc
 * @date 2019/06/13 20:50
 */
@Slf4j
public class ProcessUtils {
   /**
     * @param timeout 超時時長
     * @param fileDir 所運(yùn)行程序路徑
     * @param command 程序所要執(zhí)行的命令
     * 運(yùn)行一個外部命令,返回狀態(tài).若超過指定的超時時間,拋出TimeoutException
     */
    public static int executeProcess(final long timeout, File fileDir, final String[] command)
            throws IOException, InterruptedException, TimeoutException {
        Process process = Runtime.getRuntime().exec(command, null, fileDir);
        Worker worker = new Worker(process);
        worker.start();
        try {
            worker.join(timeout);
            if (worker.exit != null){
                return worker.exit;
            } else{
                throw new TimeoutException();
            }
        } catch (InterruptedException ex) {
            worker.interrupt();
            Thread.currentThread().interrupt();
            throw ex;
        }
        finally {
            process.destroy();
        }
    }
    
    private static class Worker extends Thread {
        private final Process process;
        private Integer exit;
        private Worker(Process process) {
            this.process = process;
        }
        @Override
        public void run() {
            InputStream errorStream = null;
            InputStream inputStream = null;
            try {
                errorStream = process.getErrorStream();
                inputStream = process.getInputStream();
                readStreamInfo(errorStream, inputStream);
                exit = process.waitFor();
                process.destroy();
                if (exit == 0) {
                    log.debug("子進(jìn)程正常完成");
                } else {
                    log.debug("子進(jìn)程異常結(jié)束");
                }
            } catch (InterruptedException ignore) {
                return;
            }
        }
    }
    /**
     * 讀取RunTime.exec運(yùn)行子進(jìn)程的輸入流 和 異常流
     * @param inputStreams 輸入流
     */
    public static void readStreamInfo(InputStream... inputStreams){
        ExecutorService executorService = Executors.newFixedThreadPool(inputStreams.length);
        for (InputStream in : inputStreams) {
            executorService.execute(new MyThread(in));
        }
        executorService.shutdown();
    }
}

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 圖解Java排序算法之3種簡單排序

    圖解Java排序算法之3種簡單排序

    這篇文章主要為大家詳細(xì)介紹了Java排序算法之3種簡單排序,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • Springboot Thymeleaf數(shù)字對象使用方法

    Springboot Thymeleaf數(shù)字對象使用方法

    這篇文章主要介紹了Springboot Thymeleaf數(shù)字對象使用方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2007-09-09
  • Java設(shè)計模式之享元模式

    Java設(shè)計模式之享元模式

    這篇文章主要為大家詳細(xì)介紹了Java設(shè)計模式之享元模式的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-08-08
  • Java對象池pool2分析PooledObjectFactory過程

    Java對象池pool2分析PooledObjectFactory過程

    文章介紹了Java中對象池化技術(shù)的背景,以Apache的Pool2庫為例,詳細(xì)講解了GenericObjectPool的構(gòu)造函數(shù)參數(shù)和PooledObjectFactory接口的實(shí)現(xiàn),通過商場里的共享充電寶的比喻,說明了池化思維的應(yīng)用
    2025-02-02
  • Mysql中備份表的多種方法

    Mysql中備份表的多種方法

    本文給大家分享Mysql中備份表的四種方法,第一種方式是小表的備份,第二種是對整個數(shù)據(jù)庫的備份與恢復(fù),第三種是對某個數(shù)據(jù)表進(jìn)行備份,每種方式給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2022-11-11
  • MyBatis-Plus實(shí)現(xiàn)多數(shù)據(jù)源的示例代碼

    MyBatis-Plus實(shí)現(xiàn)多數(shù)據(jù)源的示例代碼

    這篇文章主要介紹了MyBatis-Plus實(shí)現(xiàn)多數(shù)據(jù)源的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • Java提取2個集合中的相同和不同元素代碼示例

    Java提取2個集合中的相同和不同元素代碼示例

    這篇文章主要介紹了Java提取2個集合中的相同和不同元素代碼示例,涉及對removeall方法的簡單介紹,然后分享了主要的示例代碼,具有一定借鑒價值,需要的朋友可以參考下。
    2017-11-11
  • JAVA多線程知識匯總

    JAVA多線程知識匯總

    這篇文章主要介紹了JAVA多線程的相關(guān)資料,文中講解非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-07-07
  • SpringMVC中的DispatcherServlet初始化流程詳解

    SpringMVC中的DispatcherServlet初始化流程詳解

    這篇文章主要介紹了SpringMVC中的DispatcherServlet初始化流程詳解,DispatcherServlet這個前端控制器是一個Servlet,所以生命周期和普通的Servlet是差不多的,在一個Servlet初始化的時候都會調(diào)用該Servlet的init()方法,需要的朋友可以參考下
    2023-12-12
  • 淺談Spring Bean的基本配置

    淺談Spring Bean的基本配置

    這篇文章主要介紹了淺談Spring Bean的基本配置,文中有非常詳細(xì)的代碼示例,對正在學(xué)習(xí)java Spring的小伙伴們有非常好的幫助,需要的朋友可以參考下
    2021-05-05

最新評論

普兰县| 渝中区| 江源县| 民权县| 康保县| 西峡县| 延长县| 馆陶县| 江阴市| 扶余县| 侯马市| 大化| 措勤县| 巨野县| 福鼎市| 江山市| 枣阳市| 张北县| 定陶县| 建德市| 涞源县| 淅川县| 中西区| 吴川市| 博客| 集贤县| 凤凰县| 祁连县| 涟水县| 平舆县| 三台县| 航空| 顺平县| 两当县| 盐津县| 绥德县| 田林县| 江达县| 申扎县| 洛川县| 华容县|