成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Process工具類,提供設(shè)置timeout功能

DesGemini / 965人閱讀

摘要:類提供了執(zhí)行從進(jìn)程輸入執(zhí)行輸出到進(jìn)程等待進(jìn)程完成檢查進(jìn)程的退出狀態(tài)以及銷毀殺掉進(jìn)程的方法。解決進(jìn)程無限阻塞的方法是在執(zhí)行命令時(shí),設(shè)置一個(gè)超時(shí)時(shí)間,下面提供一個(gè)工具類,對(duì)使用進(jìn)行包裝,向外提供設(shè)置超時(shí)的接口。

在前一篇博文中,簡(jiǎn)單介紹了如何使用Process類來調(diào)用命令行的功能,那樣使用Process會(huì)有一個(gè)很大的問題,就是可能會(huì)出現(xiàn)無限阻塞的情況,永遠(yuǎn)都無法返回結(jié)果。以下是Process的API說明,注意加粗的部分。

  

ProcessBuilder.start() 和 Runtime.exec 方法創(chuàng)建一個(gè)本機(jī)進(jìn)程,并返回 Process 子類的一個(gè)實(shí)例,該實(shí)例可用來控制進(jìn)程并獲得相關(guān)信息。Process 類提供了執(zhí)行從進(jìn)程輸入、執(zhí)行輸出到進(jìn)程、等待進(jìn)程完成、檢查進(jìn)程的退出狀態(tài)以及銷毀(殺掉)進(jìn)程的方法。
創(chuàng)建進(jìn)程的方法可能無法針對(duì)某些本機(jī)平臺(tái)上的特定進(jìn)程很好地工作,比如,本機(jī)窗口進(jìn)程,守護(hù)進(jìn)程,Microsoft Windows 上的 Win16/DOS 進(jìn)程,或者 shell 腳本。創(chuàng)建的子進(jìn)程沒有自己的終端或控制臺(tái)。它的所有標(biāo)準(zhǔn) io(即 stdin、stdout 和 stderr)操作都將通過三個(gè)流 (getOutputStream()、getInputStream() 和 getErrorStream()) 重定向到父進(jìn)程。父進(jìn)程使用這些流來提供到子進(jìn)程的輸入和獲得從子進(jìn)程的輸出。因?yàn)橛行┍緳C(jī)平臺(tái)僅針對(duì)標(biāo)準(zhǔn)輸入和輸出流提供有限的緩沖區(qū)大小,如果讀寫子進(jìn)程的輸出流或輸入流迅速出現(xiàn)失敗,則可能導(dǎo)致子進(jìn)程阻塞,甚至產(chǎn)生死鎖。

解決進(jìn)程無限阻塞的方法是在執(zhí)行命令時(shí),設(shè)置一個(gè)超時(shí)時(shí)間,下面提供一個(gè)工具類,對(duì)Process使用進(jìn)行包裝,向外提供設(shè)置超時(shí)的接口。

ExecuteResult類,對(duì)執(zhí)行命令的結(jié)果進(jìn)行封裝,可以從中獲取退出碼和輸出內(nèi)容。

public class ExecuteResult {
    @Override
    public String toString() {
        return "ExecuteResult [exitCode=" + exitCode + ", executeOut="
                + executeOut + "]";
    }

    private int exitCode;
    private String executeOut;

    public ExecuteResult(int exitCode, String executeOut) {
        super();
        this.exitCode = exitCode;
        this.executeOut = executeOut;
    }

    public int getExitCode() {
        return exitCode;
    }

    public void setExitCode(int exitCode) {
        this.exitCode = exitCode;
    }

    public String getExecuteOut() {
        return executeOut;
    }

    public void setExecuteOut(String executeOut) {
        this.executeOut = executeOut;
    }

}

LocalCommandExecutorService 接口,向外暴露executeCommand()方法

public interface LocalCommandExecutorService {
    ExecuteResult executeCommand(String[] command, long timeout);
}

LocalCommandExecutorServiceImpl 實(shí)現(xiàn)類,實(shí)現(xiàn)LocalCommandExecutorService 接口的方法

public class LocalCommandExecutorServiceImpl implements
        LocalCommandExecutorService {
    static final Logger logger = LoggerFactory
            .getLogger(LocalCommandExecutorServiceImpl.class);

    static ExecutorService pool = new ThreadPoolExecutor(0, Integer.MAX_VALUE,
            3L, TimeUnit.SECONDS,
            new SynchronousQueue());

    @Override
    public ExecuteResult executeCommand(String[] command, long timeout) {
        Process process = null;
        InputStream pIn = null;
        InputStream pErr = null;
        StreamGobbler outputGobbler = null;
        StreamGobbler errorGobbler = null;
        Future executeFuture = null;
        try {
            process = Runtime.getRuntime().exec(command);
            final Process p = process;

            //close process"s output stream.
            p.getOutputStream().close();

            pIn = process.getInputStream();
            outputGobbler = new StreamGobbler(
                    pIn, "OUTPUT");
            outputGobbler.start();

            pErr = process.getErrorStream();
            errorGobbler = new StreamGobbler(pErr, "ERROR");
            errorGobbler.start();

            // create a Callable for the command"s Process which can be called
            // by an Executor
            Callable call = new Callable() {
                public Integer call() throws Exception {
                    p.waitFor();
                    return p.exitValue();
                }
            };

            // submit the command"s call and get the result from a
            executeFuture = pool.submit(call);
            int exitCode = executeFuture.get(timeout,
                    TimeUnit.MILLISECONDS);
            return new ExecuteResult(exitCode, outputGobbler.getContent());
        } catch (IOException ex) {
            String errorMessage = "The command [" + command
                    + "] execute failed.";
            logger.error(errorMessage, ex);
            return new ExecuteResult(-1, null);
        } catch (TimeoutException ex) {
            String errorMessage = "The command [" + command + "] timed out.";
            logger.error(errorMessage, ex);
            return new ExecuteResult(-1, null);
        } catch (ExecutionException ex) {
            String errorMessage = "The command [" + command
                    + "] did not complete due to an execution error.";
            logger.error(errorMessage, ex);
            return new ExecuteResult(-1, null);
        } catch (InterruptedException ex) {
            String errorMessage = "The command [" + command
                    + "] did not complete due to an interrupted error.";
            logger.error(errorMessage, ex);
            return new ExecuteResult(-1, null);
        } finally {
            if(executeFuture != null){
                try{
                executeFuture.cancel(true);
                } catch(Exception ignore){}
            }
            if(pIn != null) {
                this.closeQuietly(pIn);
                if(outputGobbler != null && !outputGobbler.isInterrupted()){
                    outputGobbler.interrupt();
                }
            }
            if(pErr != null) {
                this.closeQuietly(pErr);
                if(errorGobbler != null && !errorGobbler.isInterrupted()){
                    errorGobbler.interrupt();
                }
            }
            if (process != null) {
                process.destroy();
            }
        }
    }

      private void closeQuietly(Closeable c) {
        try {
            if (c != null)
                c.close();
        } catch (IOException e) {
        }
    }
}

StreamGobbler類,用來包裝輸入輸出流

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class StreamGobbler extends Thread {
    private static Logger logger = LoggerFactory.getLogger(StreamGobbler.class);
    private InputStream inputStream;
    private String streamType;
    private StringBuilder buf;
    private volatile boolean isStopped = false;

    /**
     * Constructor.
     * 
     * @param inputStream
     *            the InputStream to be consumed
     * @param streamType
     *            the stream type (should be OUTPUT or ERROR)
     * @param displayStreamOutput
     *            whether or not to display the output of the stream being
     *            consumed
     */
    public StreamGobbler(final InputStream inputStream, final String streamType) {
        this.inputStream = inputStream;
        this.streamType = streamType;
        this.buf = new StringBuilder();
        this.isStopped = false;
    }

    /**
     * Consumes the output from the input stream and displays the lines
     * consumed if configured to do so.
     */
    @Override
    public void run() {
        try {
            //默認(rèn)編碼為UTF-8,這里設(shè)置編碼為GBK,因?yàn)閃IN7的編碼為GBK
            InputStreamReader inputStreamReader = new InputStreamReader(
                    inputStream,"GBK");
            BufferedReader bufferedReader = new BufferedReader(
                    inputStreamReader);
            String line = null;
            while ((line = bufferedReader.readLine()) != null) {
                this.buf.append(line + "
");
            }
        } catch (IOException ex) {
            logger.trace("Failed to successfully consume and display the input stream of type "
                            + streamType + ".", ex);
        } finally {
            this.isStopped = true;
            synchronized (this) {
                notify();
            }
        }
    }

    public String getContent() {
        if(!this.isStopped){
            synchronized (this) {
                try {
                    wait();
                } catch (InterruptedException ignore) {
                }
            }
        }
        return this.buf.toString();
    }
}

測(cè)試用例

public class LocalCommandExecutorTest {
    public static void main(String[] args) {
        LocalCommandExecutorService service = new LocalCommandExecutorServiceImpl();
        String[] command = new String[]{"ping","127.0.0.1"};
        ExecuteResult result = service.executeCommand(command, 5000);
        System.out.println("退出碼:"+result.getExitCode());
        System.out.println("輸出內(nèi)容:"+result.getExecuteOut());     
    }
}

輸出結(jié)果如下:

直接在命令行執(zhí)行“ping 127.0.0.1”,結(jié)果如下:

  

Apache提供了一個(gè)開源庫(kù),對(duì)Process類進(jìn)行了封裝,也提供了設(shè)置超時(shí)的功能,建議在項(xiàng)目中使用Apache Commons Exec這個(gè)開源庫(kù)來實(shí)現(xiàn)超時(shí)功能,除了功能更強(qiáng)大外,穩(wěn)定性也有保障。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/64019.html

相關(guān)文章

  • Nodejs高性能原理(下) --- 事件循環(huán)詳解

    摘要:如果一個(gè)即時(shí)定時(shí)器是被一個(gè)正在執(zhí)行的回調(diào)排入隊(duì)列的,則該定時(shí)器直到下一次事件循環(huán)迭代才會(huì)被觸發(fā)。參數(shù)描述在事件循環(huán)的當(dāng)前回合結(jié)束時(shí)要調(diào)用的函數(shù)。事件輪詢隨后的調(diào)用,會(huì)在任何事件包括定時(shí)器之前運(yùn)行。 系列文章 Nodejs高性能原理(上) --- 異步非阻塞事件驅(qū)動(dòng)模型Nodejs高性能原理(下) --- 事件循環(huán)詳解 前言 終于開始我nodejs的博客生涯了,先從基本的原理講起.以前寫...

    newsning 評(píng)論0 收藏0
  • 使用java.lang.Process的簡(jiǎn)單例子

    摘要:在之前,都是由類處來實(shí)現(xiàn)進(jìn)程的控制管理。導(dǎo)致當(dāng)前線程等待,如有必要,一直要等到由該對(duì)象表示的進(jìn)程已經(jīng)終止。如果已終止該子進(jìn)程,此方法立即返回。為了防止進(jìn)程無限阻塞或者死鎖,使用類時(shí),需要加上超時(shí)控制,詳細(xì)內(nèi)容可以看博文工具類,提供設(shè)置功能。 ProcessBuilder類是J2SE 1.5在java.lang中新添加的一個(gè)新類,此類用于創(chuàng)建操作系統(tǒng)進(jìn)程,它提供一種啟動(dòng)和管理進(jìn)程(也就是...

    MonoLog 評(píng)論0 收藏0
  • dubbo源碼解析(九)遠(yuǎn)程通信——Transport層

    摘要:層也就是網(wǎng)絡(luò)傳輸層,在遠(yuǎn)程通信中必然會(huì)涉及到傳輸。值為,不等待消息發(fā)出,將消息放入隊(duì)列,即刻返回。三該類繼承了并且實(shí)現(xiàn)接口,是服務(wù)器抽象類。八該類是多消息處理器的抽象類。創(chuàng)建線程池設(shè)置組件的獲得實(shí)例把線程池放到 遠(yuǎn)程通訊——Transport層 目標(biāo):介紹Transport層的相關(guān)設(shè)計(jì)和邏輯、介紹dubbo-remoting-api中的transport包內(nèi)的源碼解析。 前言 先預(yù)警一...

    Magicer 評(píng)論0 收藏0
  • [Java]使用Apache Commons Execs調(diào)用腳本

    摘要:還有,需要支持字符編碼設(shè)置,在下對(duì)象調(diào)試程序很有幫助,因此,我們可以列表表示整個(gè)需求。第二種是無法設(shè)置字符編碼的,而第一種是獲得了整個(gè)標(biāo)準(zhǔn)輸出和錯(cuò)誤輸出后再設(shè)置字符編碼的。 概述 寫這篇的主要目的是為了整理和記錄,歸檔以便以后查閱。 我之前在SF上提問了一個(gè)問題:如何正確使用PipedInputStream和PipedOutputStream 問題中提到的Apache Commons ...

    chnmagnus 評(píng)論0 收藏0
  • FE.ES-理解Event Loop

    摘要:新加了一個(gè)微任務(wù)和一個(gè)宏任務(wù)在當(dāng)前執(zhí)行棧的尾部下一次之前觸發(fā)回調(diào)函數(shù)。階段這個(gè)階段主要執(zhí)行一些系統(tǒng)操作帶來的回調(diào)函數(shù),如錯(cuò)誤,如果嘗試鏈接時(shí)出現(xiàn)錯(cuò)誤,一些會(huì)把這個(gè)錯(cuò)誤報(bào)告給。 JavaScript引擎又稱為JavaScript解釋器,是JavaScript解釋為機(jī)器碼的工具,分別運(yùn)行在瀏覽器和Node中。而根據(jù)上下文的不同,Event loop也有不同的實(shí)現(xiàn):其中Node使用了libu...

    longshengwang 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<