一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - Runtime.getRuntime().exec 路徑包含空格的解決

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

2022-03-10 00:36云川之下 Java教程

這篇文章主要介紹了Runtime.getRuntime().exec 路徑包含空格的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

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

1. 現象

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

2. 原因

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

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

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

解決辦法

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

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

使用重載函數即可:

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 參數,并指定shell類型,因此需要確認shell的類型。因此根據實際環境的shell類型。

/bin/sh是什么?

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

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

 

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

背景

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

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

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

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

關于Runtime.getRuntime().exe()

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

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

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

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

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

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

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

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

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

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

先看看我們轉碼服務這里的歷史代碼:

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

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

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

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

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

阻塞陷阱之子進程阻塞

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

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

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

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

我們業務中當檢測到超時退出后就重置任務狀態為失?。ㄋ闶墙导壈桑瑢е逻@種pdf轉碼子進程阻塞的一般是pdf本身不太標準,而這個轉碼工具不能很好的兼容處理這些pdf,后面把這些有問題的pdf重新轉成標準pdf上傳測試即可以正常轉碼。

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持服務器之家。

原文鏈接:https://blog.csdn.net/m0_45406092/article/details/105654662

延伸 · 閱讀

精彩推薦
  • Java教程Java Swing組件BoxLayout布局用法示例

    Java Swing組件BoxLayout布局用法示例

    這篇文章主要介紹了Java Swing組件BoxLayout布局用法,結合實例形式分析了Swing使用BoxLayout容器進行布局的相關方法與操作技巧,需要的朋友可以參考下...

    pzy444711892021-02-05
  • Java教程Java DecimalFormat 保留小數位及四舍五入的陷阱介紹

    Java DecimalFormat 保留小數位及四舍五入的陷阱介紹

    這篇文章主要介紹了Java DecimalFormat 保留小數位及四舍五入的陷阱,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教...

    智鼎在線IT團隊5552022-02-16
  • Java教程log4j與slf4j的使用與區別詳解

    log4j與slf4j的使用與區別詳解

    這篇文章主要介紹了log4j與slf4j的使用與區別詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面...

    編程界翁老師6872021-11-02
  • Java教程使用SpringBoot2.x配置靜態文件緩存

    使用SpringBoot2.x配置靜態文件緩存

    這篇文章主要介紹了使用SpringBoot2.x配置靜態文件緩存的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教...

    小蘋果135711822021-11-26
  • Java教程關于在IDEA中SpringBoot項目中activiti工作流的使用詳解

    關于在IDEA中SpringBoot項目中activiti工作流的使用詳解

    這篇文章主要介紹了關于在IDEA中SpringBoot項目中activiti工作流的使用詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價...

    不正經的程序袁14062020-08-13
  • Java教程Java案例之隨機驗證碼功能實現實例

    Java案例之隨機驗證碼功能實現實例

    本篇文章主要介紹了Java案例之隨機驗證碼功能實現實例,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧...

    一只小蝸牛呀1532020-11-20
  • Java教程將Java程序的輸出結果寫到txt文件中的方法

    將Java程序的輸出結果寫到txt文件中的方法

    今天小編就為大家分享一篇將Java程序的輸出結果寫到txt文件中的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧...

    holdonyiyi3812021-05-18
  • Java教程SpringBoot 關于Feign的超時時間配置操作

    SpringBoot 關于Feign的超時時間配置操作

    這篇文章主要介紹了SpringBoot 關于Feign的超時時間配置操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教...

    newlangwen8602022-01-17
主站蜘蛛池模板: 日本高清在线播放一区二区三区 | 日本韩国一区二区三区 | 精品国产91高清在线观看 | 国产精品久久久久影院色老大 | 我的青梅竹马是消防员2季未增删免费 | 全日本爽视频在线 | aaaa大片| 国产成人精品免费视频软件 | 日韩国产成人 | ova催眠性指导5最新在线 | 四虎在线永久免费视频网站 | 国产青青操 | 色在线亚洲视频www 色欲麻豆国产福利精品 | 亚洲精品第一国产综合高清 | 亚洲va天堂va国产va久久 | 欧美色精品天天在线观看视频 | 92国产福利视频一区二区 | 秋霞在线观看成人高清视频51 | 精品欧美一区二区三区四区 | 99久视频| 公园吃女人奶野战视频 | 天天射天天舔 | 国产精自产拍久久久久久 | 欧美日韩一级视频 | 91丝袜足控免费网站xx | 欧美人与日本人xx在线视频 | 久久国产免费 | 草草视频人人爽 | 办公室恋情在线 | 亚洲人成绝费网站色ww | 欧美福利在线观看 | 国模李丽莎大尺度啪啪 | 欧美一级视频在线高清观看 | 日日操日日舔 | 国产精品成人va在线观看 | 极品美女aⅴ高清在线观看 极品ts赵恩静和直男激战啪啪 | 亚洲va在线va天堂va偷拍 | 欧美一级视频在线观看 | 俄罗斯引擎首页进入 | 4455永久在线视频观看 | 精品久久久久久久久免费影院 |