欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Runtime.getRuntime().exec 路徑包含空格的解決

 更新時間:2021年11月03日 11:06:05   作者:云川之下  
這篇文章主要介紹了Runtime.getRuntime().exec 路徑包含空格的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

Runtime.getRuntime().exec 路徑包含空格

1. 現(xiàn)象

java代碼通過Runtime.getRuntime().exec刪除linux上的目錄,如果路徑信息不包含空格沒有問題,但是有了空格,雖沒有報錯,但執(zhí)行沒有效果,文件夾刪不掉。

2. 原因

Runtime.getRuntime().exec語法不支持空白符和管道符"|"

不支持空白符和管道符"|"的例子:

//包含空格
String cmd = "rm -fr test 1";
// 包含管道符
String cmd2 = "netstat -antup | grep ftp";
Process ps = Runtime.getRuntime().exec(cmd);
ps.waitFor();

解決辦法

如果直接在命令行執(zhí)行的話,可以通過給完整的字符帶上單引號或雙引號,java代碼用法不適用。

[root@EMS3 ~]# rm -rf "/root/test 1"

使用重載函數(shù)即可:

public Process exec(String cmdarray[])
String cmd = "rm -fr test 1";
// 或
String cmd2 = "netstat -antup | grep ftp";
Process ps = Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c", cmd});
ps.waitFor();
...

其中-c表示cmd是一條命令

/bin/sh -c注意事項

由于增加了-c 參數(shù),并指定shell類型,因此需要確認shell的類型。因此根據(jù)實際環(huán)境的shell類型。

/bin/sh是什么?

shell編程是以"#“為注釋,但對”#!/bin/sh"卻不是。"#!/bin/sh"是對shell的聲明,說明你所用的是那種類型的shell及其路徑所在(#! /bin/sh 是指此腳本使用/bin/sh來解釋執(zhí)行,#!是特殊的表示符,其后面跟的是解釋此腳本的shell的路徑)。如果沒有聲明,則腳本將在默認的shell中執(zhí)行,默認shell是由用戶所在的系統(tǒng)定義為執(zhí)行shell腳本的shell。

如果腳本被編寫為在Kornshell ksh中運行,而默認運行shell腳本的為C shell csh,則腳本在執(zhí)行過程中很可能失敗。所以建議大家就把"#!/bin/sh"當成C 語言的main函數(shù)一樣,寫shell必須有,以使shell程序更嚴密。

Runtime.getRuntime().exec()產(chǎn)生阻塞的2個陷阱

背景

相信做java服務端開發(fā)的童鞋,經(jīng)常會遇到Java應用調(diào)用外部命令啟動一些新進程來執(zhí)行一些操作的場景,這時候就會使用到Runtime.getRuntime().exec(),然而這個方法如果不謹慎很容易掉進陷阱。

我們的一個PDF轉(zhuǎn)碼服務就踩到了這個坑掉進陷阱,這個轉(zhuǎn)碼服務主要是對pdf進行加密和轉(zhuǎn)碼成swf。這個服務上線后大部分時間都是穩(wěn)定運行的,但是隔一段時間就會死掉,然后人肉手動重啟一下服務就復活了??戳巳罩荆袝r候有一堆關于pdf轉(zhuǎn)碼過程的錯誤日志,有時候死掉的時候什么日志也沒輸出。這時候猜測可能是pdf轉(zhuǎn)碼異常導致應用掛掉的{因為這個轉(zhuǎn)碼服務一直是單線程在工作}。更深的原因大家也空沒去找。反正運營反饋上傳的pdf一直處在轉(zhuǎn)碼中很久了,一兩天了還在轉(zhuǎn)碼中,于是開發(fā)就手動重啟下服務。是的你沒看過,就是一兩天才發(fā)現(xiàn),我們的業(yè)務監(jiān)控沒作上去,因為相對迭代任務,這都算不緊急的事情了。

后來運營反饋pdf問題次數(shù)增多了,于是寫了個腳本,定時去檢查日志最后的更新時間,發(fā)現(xiàn)日志超過一個小時沒更新就重啟應用,重啟腳本沒問題,問題是應用重啟后,日志中出現(xiàn)了一堆的找不到要執(zhí)行的命令。目前也不知道為什么通過腳本去重啟動應用后,應用找不到要執(zhí)行的命令。有知道的可以告知下。

終于某一天,應用又死掉了,看了下數(shù)據(jù)庫堆積了將近2000個待轉(zhuǎn)的文件??戳讼聭萌罩敬蛄薳xe()后就再也沒內(nèi)容了,于是下狠心花了半天時間來研究下Runtime.getRuntime().exe()找了下原因,最終解決了這個問題。

關于Runtime.getRuntime().exe()

根據(jù)jdk官方文檔描述,每個Java應用都存在一個而Runtime的單例實例。這個類Runtime類封裝了應用運行時的環(huán)境,通過這個類我們的java應用可以與其運行環(huán)境相連接。

1、java應用無法創(chuàng)建自己的Runtime實例,只能通過Runtime.getRuntime()來取得當前JVM的運行時環(huán)境,這也是在Java中唯一一個得到運行時環(huán)境的方法。一旦得到了一個當前的Runtime對象的引用,就可以調(diào)用Runtime對象的方法來控制Java虛擬機的狀態(tài)和行為。

2、Runtime中的exit方法是退出當前JVM的方法,System類中的exit實際上也是通過調(diào)用Runtime.exit()來退出JVM的,這里說明一下Java對Runtime返回值的一般規(guī)則(后邊也提到了),0代表正常退出,非0代表異常中止。

3、Runtime具有的詳細方法請參考官方api,http://docs.oracle.com/javase/8/docs/api/

阻塞陷阱之Runtime.getRuntime().exe()的返回值Process

應用在調(diào)用Runtime.getRuntime().exec()這個方法會創(chuàng)建一個本機進程并返回Process子類的一個實例。該實例可用來控制該進程并獲得其相關信息。Process類提供了執(zhí)行從進程輸入、執(zhí)行輸出到進程、等待進程完成、檢查進程的退出狀態(tài)以及銷毀(殺掉)進程的方法。

官方文檔解釋了創(chuàng)建進程的方法可能無法針對某些本機平臺上的特定進程很好地工作,比如,本機窗口進程,守護進程,Microsoft Windows 上的 Win16/DOS 進程,或者 shell腳本。創(chuàng)建的子進程沒有自己的終端或控制臺。它的所有標準 io(即 stdin、stdout 和 stderr)操作都將通過三個管道重定向到父進程(也就是調(diào)用者java應用)。三個管道用于處理標準輸入流,標準輸出流,標準錯誤流。子進程在執(zhí)行過程中,會不斷的向JVM寫入標準輸出和標準錯誤輸出。java應用可以通過Process 提供的getOutputStream()、getInputStream() 和 getErrorStream()來獲得子進程輸入輸出信息。因為有些本機平臺僅針對標準輸入和輸出流提供有限的緩沖區(qū)大小,當標準輸出或者標準錯誤輸出寫滿緩存池時,程序無法繼續(xù)寫入,子進程無法正常退出。讀寫子進程的輸出流或輸入流迅速出現(xiàn)失敗,則可能導致子進程阻塞,甚至產(chǎn)生死鎖。

當調(diào)用Runtime.getRuntime().exe()后返回的Process對象除了可以多的三種輸入輸出流外,還有兩個常用的方法:

1、非阻塞方法exitValue()獲得子進程退出的狀態(tài)值(0,正常退出,非0異常退出),需要注意的是調(diào)用這個方法程序會立即得到結(jié)果,如果子進程沒有執(zhí)行完,調(diào)用這個方法會拋出IllegalThreadStateException,表示此 Process 對象表示的子進程尚未終止。

2、阻塞方法 waitFor()導致當前線程等待,直到子進程結(jié)束并返回退出狀態(tài)。如果已終止該子進程,此方法立即返回,如果沒有終止該子進程,調(diào)用的線程將被阻塞,直到退出子進程。

先看看我們轉(zhuǎn)碼服務這里的歷史代碼:

8b6068fd-a41e-4e09-b951-d89eb6de11f4

這段代碼,用同步的方法去讀取標準錯誤輸出流即相當于清空了錯誤輸出流緩沖區(qū),然而正常的標準輸出流并沒有清空,按照上面的原理解釋,阻塞的原因可能就產(chǎn)生在這里。當阻塞產(chǎn)生的時候jstack了一下線程棧信息如下圖所示。確實線程鎖在了讀取緩沖流上面了。

639048e4-46f9-4041-9b5d-a9b28d2f1f51?imageView&thumbnail=980x0

這種情況網(wǎng)上通用的解決方法就是異步開兩個線程去讀取正常的輸出和錯誤輸出流信息,清空緩沖區(qū),參考了大家的解決方法,下圖是修改后的方案,ProcessClearStream是一個異步線程,主要做的是將標準inputSream讀取完畢。

6b31a150-06a0-4a5f-b7a5-ffd4b56e8348?imageView&thumbnail=980x0

阻塞陷阱之子進程阻塞

通過上面的代碼優(yōu)化后還是發(fā)現(xiàn)有轉(zhuǎn)碼阻塞的現(xiàn)象出現(xiàn),而且發(fā)現(xiàn)每次阻塞都出現(xiàn)在固定的幾個pdf上,測試發(fā)現(xiàn)重啟應用后主要轉(zhuǎn)到那幾個特定的pdf時候,轉(zhuǎn)碼服務必掛無疑(通常一個pdf轉(zhuǎn)碼只需要幾十秒,而這個阻塞持續(xù)幾個小時,不人為干預它就可能無限阻塞下去)。所以重啟應用也不管用了,只能跳過這幾個pdf應用才行,于是在測試環(huán)境測試這幾個pdf,每次阻塞的時候再jstack發(fā)現(xiàn)應用阻塞在proc.waitFor(),再也沒其他錯誤信息了。查看了官方api,Process的waitFor方法本身會阻塞直到子進程正?;虍惓M顺?,到這里,應該可以推斷是子進程無限阻塞下去了,導致waitFor一直阻塞中。為了驗證這個推斷,直接在終端kill掉這個子進程,然后再查看日志,發(fā)現(xiàn)轉(zhuǎn)碼服務又繼續(xù)工作了。

有了上面的結(jié)論,一個簡單的思路也就有了,我需要檢測子進程狀態(tài),如果發(fā)現(xiàn)子進程有阻塞狀態(tài)就kill掉(因為這個轉(zhuǎn)碼腳本比較老,要拿他的堆棧信息比較麻煩,所以kill掉是最簡單直接暴力效率高的方法)。將這個想法和同事聊了下,萬能的Java肯定可以干這事,大概思路就啟動個線程去監(jiān)控process的waitFor的阻塞時間,超過設置時間,就干掉了子進程,這不是Java線程池ExecutorService類配合Future接口來干的事情么。同事按照這個思路網(wǎng)上找了下現(xiàn)成的代碼,于是照著這個這個方法抄襲了一下,下面貼下關鍵的代碼:

9d08d3e6-2cb9-48c7-b9fa-2da654a68d62

當waitFor超時線程中斷的的時候再調(diào)用process的destroy()銷毀子進程。這個方案上線后,截至目前一周多時間轉(zhuǎn)碼服務穩(wěn)定運行,沒在出現(xiàn)以前的服務死掉的情況。

我們業(yè)務中當檢測到超時退出后就重置任務狀態(tài)為失敗(算是降級吧),導致這種pdf轉(zhuǎn)碼子進程阻塞的一般是pdf本身不太標準,而這個轉(zhuǎn)碼工具不能很好的兼容處理這些pdf,后面把這些有問題的pdf重新轉(zhuǎn)成標準pdf上傳測試即可以正常轉(zhuǎn)碼。

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

相關文章

  • SpringBoot項目Jar包如何瘦身部署的實現(xiàn)

    SpringBoot項目Jar包如何瘦身部署的實現(xiàn)

    這篇文章主要介紹了SpringBoot項目Jar包如何瘦身部署的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-09-09
  • 劍指Offer之Java算法習題精講二叉樹與N叉樹

    劍指Offer之Java算法習題精講二叉樹與N叉樹

    跟著思路走,之后從簡單題入手,反復去看,做過之后可能會忘記,之后再做一次,記不住就反復做,反復尋求思路和規(guī)律,慢慢積累就會發(fā)現(xiàn)質(zhì)的變化
    2022-03-03
  • JavaSE圖像驗證碼簡單識別程序詳解

    JavaSE圖像驗證碼簡單識別程序詳解

    這篇文章主要為大家詳細介紹了JavaSE圖像驗證碼簡單識別程序,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • Java 指定微信好友自動發(fā)送消息的實現(xiàn)示例

    Java 指定微信好友自動發(fā)送消息的實現(xiàn)示例

    這篇文章主要介紹了Java 指定微信好友自動發(fā)送消息的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-10-10
  • SpringBoot配置使Mybatis打印SQL執(zhí)行時的實際參數(shù)值操作

    SpringBoot配置使Mybatis打印SQL執(zhí)行時的實際參數(shù)值操作

    這篇文章主要介紹了SpringBoot配置使Mybatis打印SQL執(zhí)行時的實際參數(shù)值操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • 基于@Autowierd(自動裝配)的使用說明

    基于@Autowierd(自動裝配)的使用說明

    這篇文章主要介紹了@Autowierd(自動裝配)的使用說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • 解決fastjson泛型轉(zhuǎn)換報錯的解決方法

    解決fastjson泛型轉(zhuǎn)換報錯的解決方法

    這篇文章主要介紹了解決fastjson泛型轉(zhuǎn)換報錯的解決方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-11-11
  • Lombok在idea中的使用教程

    Lombok在idea中的使用教程

    Lombok是一個可以通過簡單的注解形式,來幫助我們簡化消除一些必須有但顯得很臃腫(如果getter、setter方法)的Java代碼的工具,通過使用對應的注解,可以在編譯源碼的時候生成對應的方法,這篇文章主要介紹了Lombok在idea中的使用,需要的朋友可以參考下
    2023-03-03
  • Java多種經(jīng)典排序算法(含動態(tài)圖)

    Java多種經(jīng)典排序算法(含動態(tài)圖)

    排序算法是老生常談的了,但是在面試中也有會被問到,例如有時候,在考察算法能力的時候,不讓你寫算法,就讓你描述一下,某個排序算法的思想以及時間復雜度或空間復雜度。我就遇到過,直接問快排的,所以這次我就總結(jié)梳理一下經(jīng)典的十大排序算法以及它們的模板代碼
    2021-04-04
  • Java8新特性之Optional使用詳解

    Java8新特性之Optional使用詳解

    這篇文章主要介紹了Java8新特性之Optional使用詳解,為了解決空指針異常更加優(yōu)雅,Java8?提供了?Optional?類庫,Optional?實際上是個容器,它可以保存類型T的值,或者僅僅保存null,,需要的朋友可以參考下
    2023-08-08

最新評論