كيف يمكن لبرنامج Java الحصول على معرف العملية الخاص به؟

StackOverflow https://stackoverflow.com/questions/35842

  •  09-06-2019
  •  | 
  •  

سؤال

كيف يمكنني الحصول على معرف عملية Java الخاصة بي؟

أعلم أن هناك العديد من الاختراقات المعتمدة على النظام الأساسي، لكنني أفضل حلاً أكثر عمومية.

هل كانت مفيدة؟

المحلول

لا توجد طريقة مستقلة عن النظام الأساسي يمكن ضمان عملها في جميع تطبيقات jvm.ManagementFactory.getRuntimeMXBean().getName() يبدو أنه الحل الأفضل (الأقرب).إنها قصيرة، و من المحتمل يعمل في كل تطبيق في الاستخدام على نطاق واسع.

على Linux+windows تقوم بإرجاع قيمة مثل 12345@hostname (12345 كونه معرف العملية).احذر رغم ذلك وفقا للمستندات, ، لا توجد ضمانات حول هذه القيمة:

إرجاع الاسم الذي يمثل جهاز Java الظاهري قيد التشغيل.يمكن أن تكون سلسلة الاسم التي تم إرجاعها أي سلسلة تعسفية ويمكن لتنفيذ الجهاز الظاهري Java اختيار تضمين معلومات مفيدة خاصة بالنظام الأساسي في سلسلة الاسم التي تم إرجاعها.يمكن أن يكون لكل جهاز افتراضي قيد التشغيل اسم مختلف.

في جافا 9 الجديد واجهة برمجة التطبيقات للعملية ممكن استخدامه:

long pid = ProcessHandle.current().pid();

نصائح أخرى

يمكنك استخدام جينا.لسوء الحظ، لا توجد واجهة برمجة تطبيقات JNA مشتركة للحصول على معرف العملية الحالي حتى الآن، ولكن كل منصة بسيطة جدًا:

شبابيك

تأكد من أن لديك jna-platform.jar ثم:

int pid = Kernel32.INSTANCE.GetCurrentProcessId();

يونكس

يعلن:

private interface CLibrary extends Library {
    CLibrary INSTANCE = (CLibrary) Native.loadLibrary("c", CLibrary.class);   
    int getpid ();
}

ثم:

int pid = CLibrary.INSTANCE.getpid();

جافا 9

تحت جافا 9 الجديد واجهة برمجة التطبيقات للعملية يمكن استخدامها للحصول على معرف العملية الحالية.أولاً، يمكنك الحصول على مؤشر للعملية الحالية، ثم الاستعلام عن PID:

long pid = ProcessHandle.current().pid();

إليك طريقة الباب الخلفي التي قد لا يعمل مع جميع الأجهزة الافتراضية ولكن يجب أن يعمل على نظامي التشغيل Linux وWindows (المثال الأصلي هنا):

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);

يحاول سيجار .واجهات برمجة التطبيقات واسعة النطاق للغاية.رخصة أباتشي 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();
    }

يحاول الأسلوب التالي استخراج PID من 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;
}

اتصل وحسب getProcessId("<PID>"), ، على سبيل المثال.

بالنسبة لـ JVM الأقدم، في 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";
}

يمكنك الاطلاع على مشروعي: JavaSysMon على جيثب.يوفر معرف العملية ومجموعة من الأشياء الأخرى (استخدام وحدة المعالجة المركزية واستخدام الذاكرة) عبر الأنظمة الأساسية (حاليًا Windows وMac OSX وLinux وSolaris)

منذ Java 9 هناك طريقة Process.getPid() والتي تقوم بإرجاع المعرف الأصلي للعملية:

public abstract class Process {

    ...

    public long getPid();
}

للحصول على معرف العملية لعملية Java الحالية، يمكن للمرء استخدام ملف ProcessHandle واجهه المستخدم:

System.out.println(ProcessHandle.current().pid());

في سكالا:

import sys.process._
val pid: Long = Seq("sh", "-c", "echo $PPID").!!.trim.toLong

من المفترض أن يوفر لك هذا حلاً بديلاً على أنظمة Unix حتى يتم إصدار Java 9.(أعلم أن السؤال كان يتعلق بـ Java، ولكن نظرًا لعدم وجود سؤال مكافئ لـ Scala، أردت ترك هذا لمستخدمي Scala الذين قد يتعثرون في نفس السؤال.)

من أجل اكتمال هناك غلاف في التمهيد الربيع ل

String jvmName = ManagementFactory.getRuntimeMXBean().getName();
return jvmName.split("@")[0];

حل.إذا كان هناك عدد صحيح مطلوبًا، فيمكن تلخيص ذلك في سطر واحد:

int pid = Integer.parseInt(ManagementFactory.getRuntimeMXBean().getName().split("@")[0]);

إذا كان شخص ما يستخدم Spring Boot بالفعل، فقد يستخدمه org.springframework.boot.ApplicationPid

ApplicationPid pid = new ApplicationPid();
pid.toString();

يقوم الأسلوب toString() بطباعة معرف المنتج أو "؟؟؟".

تمت مناقشة التحذيرات باستخدام ManagementFactory في إجابات أخرى بالفعل.

public static long getPID() {
    String processName = java.lang.management.ManagementFactory.getRuntimeMXBean().getName();
    if (processName != null && processName.length() > 0) {
        try {
            return Long.parseLong(processName.split("@")[0]);
        }
        catch (Exception e) {
            return 0;
        }
    }

    return 0;
}

آخر ما وجدته هو أن هناك خاصية النظام مُسَمًّى sun.java.launcher.pid وهو متاح على الأقل في نظام التشغيل Linux.خطتي هي استخدام ذلك وإذا لم يتم العثور عليه لاستخدام JMX bean.

java.lang.management.ManagementFactory.getRuntimeMXBean().getName().split("@")[0]

يعتمد ذلك على المكان الذي تبحث منه عن المعلومات.

إذا كنت تبحث عن المعلومات من وحدة التحكم، فيمكنك استخدام الأمر jps.يعطي الأمر إخراجًا مشابهًا لأمر Unix ps ويأتي مع JDK منذ أن أعتقد 1.5

إذا كنت تنظر من العملية، فمن المحتمل أن يكون RuntimeMXBean (كما قال Wouter Coekaerts) هو خيارك الأفضل.يكون الإخراج من getName() على Windows باستخدام Sun JDK 1.6 u7 بالصيغة [PROCESS_ID]@[MACHINE_NAME].ومع ذلك، يمكنك محاولة تنفيذ jps وتحليل النتيجة من ذلك:

String jps = [JDK HOME] + "\\bin\\jps.exe";
Process p = Runtime.getRuntime().exec(jps);

إذا تم التشغيل بدون خيارات، فيجب أن يكون الإخراج هو معرف العملية متبوعًا بالاسم.

استنادًا إلى أشوين جايابراكاش إجابة (+1) حول Apache 2.0 المرخص SIGAR, ، إليك كيفية استخدامه للحصول على معرف المنتج (PID) للعملية الحالية فقط:

import org.hyperic.sigar.Sigar;

Sigar sigar = new Sigar();
long pid = sigar.getPid();
sigar.close();

على الرغم من أنه لا يعمل على جميع المنصات، إلا أنه يعمل عليها Linux وWindows وOS X ومنصات Unix المختلفة كما هو موضح هنا.

هذا هو الكود JConsole، ومن المحتمل أن يستخدمه jps وVisualVM.ويستخدم فئات منsun.jvmstat.monitor.* الحزمة، من 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;
    }
}

هناك عدد قليل من المصيد:

  • ال tool.jar هي مكتبة موزعة باستخدام Oracle JDK ولكن ليس JRE!
  • لا يمكنك الحصول على tool.jar من مافن الريبو.يعد تكوينه باستخدام Maven أمرًا صعبًا بعض الشيء
  • ال tool.jar ربما يحتوي على رمز تعتمد على النظام الأساسي (الأصلي؟) بحيث لا يمكن توزيعه بسهولة
  • يتم تشغيله على افتراض أن جميع تطبيقات JVM (المحلية) قيد التشغيل "قابلة للمراقبة".يبدو أن ذلك من Java 6 جميع التطبيقات عمومًا (إلا إذا قمت بتكوين عكس ذلك بنشاط)
  • ربما يعمل فقط مع Java 6+
  • Eclipse لا تنشر الفصل الرئيسي ، لذلك لن تحصل على Eclipse Pid بسهولة في مراقبة Vmutil؟

تحديث:لقد تأكدت للتو من أن JPS يستخدم بهذه الطريقة، وهي مكتبة Jvmstat (جزء من tool.jar).لذلك ليست هناك حاجة لاستدعاء JPS كعملية خارجية، اتصل بمكتبة Jvmstat مباشرة كما يظهر في المثال الخاص بي.يمكنك أيضًا الحصول على قائمة بجميع أجهزة JVM التي يتم تشغيلها على المضيف المحلي بهذه الطريقة.انظر جي بي اس مصدر الرمز:

يمكنك المحاولة getpid() في جي إن آر-بوسيكس.

يحتوي على غلاف Windows POSIX الذي يستدعي getpid() من libc.

أعلم أن هذا موضوع قديم، لكنني أردت استدعاء واجهة برمجة التطبيقات (API) هذه للحصول على معرف المنتج (بالإضافة إلى المعالجة الأخرى لعملية Java في وقت التشغيل) التي تتم إضافتها إلى فئة العملية في JDK 9: http://openjdk.java.net/jeps/102

لقد وجدت حلاً قد يكون بمثابة حالة حافة إلى حد ما ولم أجربه على نظام تشغيل آخر غير Windows 10، ولكن أعتقد أنه يستحق الملاحظة.

إذا وجدت نفسك تعمل مع J2V8 وnodejs، يمكنك تشغيل وظيفة جافا سكريبت بسيطة لتعيد لك معرف عملية جافا.

هنا مثال:

public static void main(String[] args) {
    NodeJS nodeJS = NodeJS.createNodeJS();
    int pid = nodeJS.getRuntime().executeIntegerScript("process.pid;\n");
    System.out.println(pid);
    nodeJS.release();
}

إضافة إلى حلول أخرى.

مع جافا 10، للحصول على process id

final RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
final long pid = runtime.getPid();
out.println("Process ID is '" + pid);

هنا هو الحل الخاص بي:

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;
    }

هذا هو ما استخدمته عندما كان لدي متطلبات مماثلة.يؤدي هذا إلى تحديد PID لعملية Java بشكل صحيح.اسمح لكود Java الخاص بك بإنشاء خادم على رقم منفذ محدد مسبقًا ثم قم بتنفيذ أوامر نظام التشغيل لمعرفة PID الذي يستمع على المنفذ.لينكس

netstat -tupln | grep portNumber
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top