2011-12-08

Tags: 程式語言 , java

在作業系統中查出目前正在執行的java process到底是哪個Main class啟動,其實有點麻煩。如果在linux裡用ps指令去查,只會看到命名為java的process跟其對應的PID,如果是在windows裡,把工作管理員叫出來看,也是只能看到命名為java的process跟其對應的PID。如果你的作業系統同時跑了好儿支獨立的java程式,這時麻煩就來了,你只會看到一堆java process,搞不清對應的程式到底是誰...Orz。

解法當然是有,最簡單的方式就是用jconsole去查,它會秀出所有local端的java process、對應的PID、還有啟動它的Main class。執行時的畫面如下所示。


不過...在沒有裝x-window的linux上,這招就沒用啦。所以最省資源且最方便的方式應該是要用jdk內附的jps指令來查。jps的完整用法可以去官網查( 按此)。執行時的畫面如下所示。
C:\Users\cloudtu>jps -l
1640 sun.tools.jps.Jps
6684 sun.tools.jconsole.JConsole
1752
6664 org.eclipse.jetty.start.Main

如果你的程式(同個Main class)在同一時間只許可一個java process啟動它,寫程式去呼叫外部的jps指令來幫忙做這件事,則是一個很方便的作法。可參考下列實作程式碼。

public class OSUtil
{
private static final Logger logger = Logger.getLogger(OSUtil.class);

private OSUtil()
{
}

/**
* 執行作業系統中的Console command,並將執行結果轉換成字串回傳
*
* @param cmdStr Console command
*
* @return 執行結果
*
* @throws RuntimeException
*/
public static String execCmd(String cmdStr)
{
try
{
Process proc = Runtime.getRuntime().exec(cmdStr);
InputStream is = proc.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line = null;
StringBuilder result = new StringBuilder();
while ((line = br.readLine()) != null)
{
result.append(line + "\n");
}
br.close();

return result.toString();
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}

/**
* 利用JPS指令查詢特定的MainClass目前被啟動了儿個Java process
*
* @param mainClass Main Class
*
* @return Java process amount
*
* @throws RuntimeException
*/
public static int queryJavaProcessAmount(Class mainClass){
String jpsCmd = System.getProperty("java.home").replaceAll("\\\\", "/").replaceAll("jre", "") + "bin/jps -l"; //JPS指令的fully path
logger.debug("jpsCmd : " + jpsCmd);

String jpsExecuteResult = execCmd(jpsCmd);
logger.debug("jpsExecuteResult : " + jpsExecuteResult);

int javaProcessAmount = 0;
int foundIndex = 0;
String key = mainClass.getName();
while(true){
foundIndex = jpsExecuteResult.indexOf(key, foundIndex);
if(foundIndex >= 0){
javaProcessAmount++;
}
else{
break;
}

if(foundIndex + key.length() <= jpsExecuteResult.length() - 1){
foundIndex = foundIndex + key.length();
}
else{
break;
}
}
return javaProcessAmount;
}
}

jps蠻好用的,不過有個地方要注意一下。我發現如果作業系統是windows,然後檔案格式又是早期的FAT或FAT32的話,jps指令會無法查出執行的java process所對應的PID是誰。不過...這年頭應該沒多少人把windows裝在這種格式之上了才對,所以踩到地雷的機會應該不大...:)