国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

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

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個待轉的文件。看了下應用日志打了exe()后就再也沒內容了,于是下狠心花了半天時間來研究下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

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 青青国产视频 | 中国毛片基地 | 2024国产精品 | 91精品国产高清一区二区三区 | 欧美在线国产 | 欧美日韩成人精品 | 免费网站在线 | 天天天干夜夜夜操 | 中文字幕大全 | 欧美影 | 久久九 | 日韩精品小视频 | av不卡电影在线观看 | 在线视频 中文字幕 | 久久精品一 | 91亚洲国产成人久久精品网站 | 精品一区二区久久久久久久网站 | 成人av一区二区亚洲精 | 亚洲精品影视 | 川上优av中文字幕一区二区 | 国产精品免费视频一区二区三区 | 午夜影院在线播放 | 欧美一区二区在线观看视频 | 亚洲精品男人的天堂 | 欧美一区2区 | av在线一区二区三区 | 欧美一级二级三级视频 | 来个毛片 | 91久久精品国产91久久 | 欧洲精品码一区二区三区免费看 | 欧州一级片| 久久国产区 | 免费成人av在线 | 综合久久av | 国产精品欧美久久久久一区二区 | 久艹精品 | 精品国产子伦久久久久久小说 | 午夜爱爱毛片xxxx视频免费看 | 亚洲精品九九 | 成人在线一级片 | 欧美成人精品一区 |