Làm cách nào để có id của quy trình Java của tôi?
Tôi biết có một số hack phụ thuộc vào nền tảng, nhưng tôi thích một giải pháp chung hơn.
Làm cách nào để có id của quy trình Java của tôi?
Tôi biết có một số hack phụ thuộc vào nền tảng, nhưng tôi thích một giải pháp chung hơn.
Câu trả lời:
Không tồn tại cách độc lập với nền tảng nào có thể được đảm bảo để hoạt động trong tất cả các triển khai jvm.
ManagementFactory.getRuntimeMXBean().getName()
trông giống như giải pháp tốt nhất (gần nhất) Nó ngắn và có thể hoạt động trong mọi triển khai được sử dụng rộng rãi.
Trên linux + windows, nó trả về một giá trị như 12345@hostname
( 12345
là id quá trình). Hãy coi chừng rằng theo các tài liệu , không có gì đảm bảo về giá trị này:
Trả về tên đại diện cho máy ảo Java đang chạy. Chuỗi tên được trả về có thể là bất kỳ chuỗi tùy ý nào và việc triển khai máy ảo Java có thể chọn để nhúng thông tin hữu ích dành riêng cho nền tảng trong chuỗi tên được trả về. Mỗi máy ảo đang chạy có thể có một tên khác nhau.
Trong Java 9 , API quy trình mới có thể được sử dụng:
long pid = ProcessHandle.current().pid();
Bạn có thể sử dụng JNA . Thật không may, chưa có API JNA chung để nhận ID quy trình hiện tại, nhưng mỗi nền tảng khá đơn giản:
Hãy chắc chắn rằng bạn có jna-platform.jar
:
int pid = Kernel32.INSTANCE.GetCurrentProcessId();
Khai báo:
private interface CLibrary extends Library {
CLibrary INSTANCE = (CLibrary) Native.loadLibrary("c", CLibrary.class);
int getpid ();
}
Sau đó:
int pid = CLibrary.INSTANCE.getpid();
Trong Java 9, API quy trình mới có thể được sử dụng để lấy ID quy trình hiện tại. Trước tiên, bạn lấy một điều khiển cho quy trình hiện tại, sau đó truy vấn PID:
long pid = ProcessHandle.current().pid();
getpid()
giải pháp cũng làm việc cho OS X, với một cuộc gọi JNA vào thư viện "hệ thống".
error: cannot find symbol
cho jdk9
Đây là một phương thức cửa sau có thể không hoạt động với tất cả các máy ảo nhưng sẽ hoạt động trên cả linux và windows ( ví dụ ban đầu ở đây ):
java.lang.management.RuntimeMXBean runtime =
java.lang.management.ManagementFactory.getRuntimeMXBean();
java.lang.reflect.Field jvm = runtime.getClass().getDeclaredField("jvm");
jvm.setAccessible(true);
sun.management.VMManagement mgmt =
(sun.management.VMManagement) jvm.get(runtime);
java.lang.reflect.Method pid_method =
mgmt.getClass().getDeclaredMethod("getProcessId");
pid_method.setAccessible(true);
int pid = (Integer) pid_method.invoke(mgmt);
getDeclaredMethod
trên Object trả về jvm.get(runtime)
.
Hãy thử Sigar . API rất rộng. Giấy phép Apache 2.
private Sigar sigar;
public synchronized Sigar getSigar() {
if (sigar == null) {
sigar = new Sigar();
}
return sigar;
}
public synchronized void forceRelease() {
if (sigar != null) {
sigar.close();
sigar = null;
}
}
public long getPid() {
return getSigar().getPid();
}
Phương pháp sau đây cố gắng trích xuất PID từ java.lang.management.ManagementFactory
:
private static String getProcessId(final String fallback) {
// Note: may fail in some JVM implementations
// therefore fallback has to be provided
// something like '<pid>@<hostname>', at least in SUN / Oracle JVMs
final String jvmName = ManagementFactory.getRuntimeMXBean().getName();
final int index = jvmName.indexOf('@');
if (index < 1) {
// part before '@' empty (index = 0) / '@' not found (index = -1)
return fallback;
}
try {
return Long.toString(Long.parseLong(jvmName.substring(0, index)));
} catch (NumberFormatException e) {
// ignore
}
return fallback;
}
Chỉ cần gọi getProcessId("<PID>")
, ví dụ.
Đối với JVM cũ hơn, trong linux ...
private static String getPid() throws IOException {
byte[] bo = new byte[256];
InputStream is = new FileInputStream("/proc/self/stat");
is.read(bo);
for (int i = 0; i < bo.length; i++) {
if ((bo[i] < '0') || (bo[i] > '9')) {
return new String(bo, 0, i);
}
}
return "-1";
}
int pid = Integer.parseInt(new File("/proc/self").getCanonicalFile().getName());
. Tại sao các con quay thêm?
getCanonicalFile()
phương pháp chuyển đổi "bản thân" thành PID?
Bạn có thể kiểm tra dự án của tôi: JavaSysMon trên GitHub. Nó cung cấp id quá trình và một loạt các thứ khác (sử dụng CPU, sử dụng bộ nhớ) đa nền tảng (hiện tại là Windows, Mac OSX, Linux và Solaris)
Vì Java 9 có một phương thức Process.getPid () trả về ID gốc của một quy trình:
public abstract class Process {
...
public long getPid();
}
Để lấy ID tiến trình của quy trình Java hiện tại, người ta có thể sử dụng ProcessHandle
giao diện:
System.out.println(ProcessHandle.current().pid());
Trong Scala:
import sys.process._
val pid: Long = Seq("sh", "-c", "echo $PPID").!!.trim.toLong
Điều này sẽ cung cấp cho bạn một cách giải quyết trên các hệ thống Unix cho đến khi Java 9 được phát hành. (Tôi biết, câu hỏi là về Java, nhưng vì không có câu hỏi tương đương với Scala, tôi muốn để lại câu hỏi này cho những người dùng Scala có thể vấp vào cùng một câu hỏi.)
Để hoàn thiện, có một trình bao bọc trong Spring Boot cho
String jvmName = ManagementFactory.getRuntimeMXBean().getName();
return jvmName.split("@")[0];
giải pháp. Nếu một số nguyên là bắt buộc, thì điều này có thể được tóm tắt thành một lớp lót:
int pid = Integer.parseInt(ManagementFactory.getRuntimeMXBean().getName().split("@")[0]);
Nếu ai đó đã sử dụng Spring boot, cô ấy / anh ấy có thể sử dụng org.springframework.boot.ApplicationPid
ApplicationPid pid = new ApplicationPid();
pid.toString();
Phương thức toString () in pid hoặc '???'.
Hãy cẩn thận khi sử dụng ManagementFactory đã được thảo luận trong các câu trả lời khác.
Cái mới nhất tôi đã tìm thấy là có một thuộc tính hệ thống được gọi sun.java.launcher.pid
là có sẵn ít nhất trên linux. Kế hoạch của tôi là sử dụng nó và nếu nó không được tìm thấy để sử dụng JMX bean
.
Nó phụ thuộc vào nơi bạn đang tìm kiếm thông tin từ.
Nếu bạn đang tìm kiếm thông tin từ bàn điều khiển, bạn có thể sử dụng lệnh jps. Lệnh cho đầu ra tương tự như lệnh Unix ps và đi kèm với JDK vì tôi tin 1.5
Nếu bạn đang tìm kiếm từ quy trình thì RuntimeMXBean (như đã nói của Wouter Coekaerts) có lẽ là sự lựa chọn tốt nhất của bạn. Đầu ra từ getName () trên Windows bằng Sun JDK 1.6 u7 có dạng [PROCESS_ID] @ [MachINE_NAME]. Tuy nhiên, bạn có thể thử thực thi jps và phân tích kết quả từ đó:
String jps = [JDK HOME] + "\\bin\\jps.exe";
Process p = Runtime.getRuntime().exec(jps);
Nếu chạy không có tùy chọn, đầu ra sẽ là id quá trình theo sau là tên.
Đây là mã JConsole, và có khả năng sử dụng jps và VisualVM. Nó sử dụng các lớp từ
sun.jvmstat.monitor.*
gói, từ tool.jar
.
package my.code.a003.process;
import sun.jvmstat.monitor.HostIdentifier;
import sun.jvmstat.monitor.MonitorException;
import sun.jvmstat.monitor.MonitoredHost;
import sun.jvmstat.monitor.MonitoredVm;
import sun.jvmstat.monitor.MonitoredVmUtil;
import sun.jvmstat.monitor.VmIdentifier;
public class GetOwnPid {
public static void main(String[] args) {
new GetOwnPid().run();
}
public void run() {
System.out.println(getPid(this.getClass()));
}
public Integer getPid(Class<?> mainClass) {
MonitoredHost monitoredHost;
Set<Integer> activeVmPids;
try {
monitoredHost = MonitoredHost.getMonitoredHost(new HostIdentifier((String) null));
activeVmPids = monitoredHost.activeVms();
MonitoredVm mvm = null;
for (Integer vmPid : activeVmPids) {
try {
mvm = monitoredHost.getMonitoredVm(new VmIdentifier(vmPid.toString()));
String mvmMainClass = MonitoredVmUtil.mainClass(mvm, true);
if (mainClass.getName().equals(mvmMainClass)) {
return vmPid;
}
} finally {
if (mvm != null) {
mvm.detach();
}
}
}
} catch (java.net.URISyntaxException e) {
throw new InternalError(e.getMessage());
} catch (MonitorException e) {
throw new InternalError(e.getMessage());
}
return null;
}
}
Có một vài lưu ý:
tool.jar
là một thư viện được phân phối với Oracle JDK nhưng không phải JRE!tool.jar
từ Maven repo; cấu hình nó với Maven là một chút khó khăntool.jar
lẽ chứa mã phụ thuộc nền tảng (bản địa?) Nên không dễ phân phốiCẬP NHẬT: Tôi vừa kiểm tra hai lần rằng JPS sử dụng theo cách này, đó là thư viện Jvmstat (một phần của tool.jar). Vì vậy, không cần phải gọi JPS là quy trình bên ngoài, hãy gọi thư viện Jvmstat trực tiếp như ví dụ của tôi cho thấy. Bạn cũng có thể lấy danh sách tất cả các JVM chạy trên localhost theo cách này. Xem mã nguồn JPS :
Tôi đang thêm điều này, cho các giải pháp khác.
process id
final RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
final long pid = runtime.getPid();
out.println("Process ID is '" + pid);
Dựa trên câu trả lời của Ashwin Jayaprakash (+1) về Apache 2.0 được cấp phép SIGAR
, đây là cách tôi sử dụng nó để chỉ nhận được PID của quy trình hiện tại:
import org.hyperic.sigar.Sigar;
Sigar sigar = new Sigar();
long pid = sigar.getPid();
sigar.close();
Mặc dù nó không hoạt động trên tất cả các nền tảng, nhưng nó hoạt động trên Linux, Windows, OS X và các nền tảng Unix khác nhau như được liệt kê ở đây .
Tôi biết đây là một luồng cũ, nhưng tôi muốn gọi API đó để lấy PID (cũng như các thao tác khác của quy trình Java khi chạy) đang được thêm vào lớp Process trong JDK 9: http: // openjdk. java.net/jeps/102
Tôi đã tìm thấy một giải pháp có thể là một chút của một trường hợp cạnh và tôi đã không thử nó trên hệ điều hành khác ngoài Windows 10, nhưng tôi nghĩ rằng nó đáng chú ý.
Nếu bạn thấy mình làm việc với J2V8 và nodejs, bạn có thể chạy một hàm javascript đơn giản trả về cho bạn bản chính của quy trình java.
Đây là một ví dụ:
public static void main(String[] args) {
NodeJS nodeJS = NodeJS.createNodeJS();
int pid = nodeJS.getRuntime().executeIntegerScript("process.pid;\n");
System.out.println(pid);
nodeJS.release();
}
Đây là giải pháp của tôi:
public static boolean isPIDInUse(int pid) {
try {
String s = null;
int java_pid;
RuntimeMXBean rt = ManagementFactory.getRuntimeMXBean();
java_pid = Integer.parseInt(rt.getName().substring(0, rt.getName().indexOf("@")));
if (java_pid == pid) {
System.out.println("In Use\n");
return true;
}
} catch (Exception e) {
System.out.println("Exception: " + e.getMessage());
}
return false;
}
Đây là những gì tôi đã sử dụng khi tôi có yêu cầu tương tự. Điều này xác định chính xác PID của quy trình Java. Hãy để mã java của bạn sinh ra một máy chủ trên một số cổng được xác định trước và sau đó thực thi các lệnh OS để tìm ra cách nghe PID trên cổng. Dành cho Linux
netstat -tupln | grep portNumber
bash -c 'echo $PPID'
hoặc câu trả lời