83

次のコードでプロセスを開始しました

 ProcessBuilder pb = new ProcessBuilder("cmd", "/c", "path");
 try {
     Process p = pb.start();       
 } 
 catch (IOException ex) {}

ここで、開始したばかりのプロセスの pid を知る必要があります。

4

18 に答える 18

30

このためのパブリック API はまだありません。Sunバグ 4244896、Sunバグ4250622 を参照してください。

回避策として:

Runtime.exec(...)

タイプのオブジェクトを返します

java.lang.Process

Process クラスは抽象的であり、オペレーティング システム用に設計された Process のサブクラスが返されます。たとえば、Mac では、java.lang.UnixProcessというプライベート フィールドがあるものを返しますpid。Reflection を使用すると、このフィールドの値を簡単に取得できます。これは確かにハックですが、役立つかもしれません。PIDとにかくあなたは何のために必要ですか?

于 2011-01-20T17:48:10.930 に答える
24

このページには HOWTO があります:

http://www.golesny.de/p/code/javagetpid

Windows の場合:

Runtime.exec(..)

"java.lang.Win32Process") または "java.lang.ProcessImpl" のインスタンスを返します

どちらもプライベート フィールド「ハンドル」を持っています。

これは、プロセスの OS ハンドルです。PID を照会するには、この + Win32 API を使用する必要があります。そのページには、その方法の詳細が記載されています。

于 2011-04-07T09:32:24.050 に答える
8

ほとんどのプラットフォームで作業している間、非常に防弾に見える解決策を見つけたと思います。これがアイデアです:

  1. 新しいプロセスを生成する/プロセスを強制終了する前に取得する JVM 全体のミューテックスを作成します。
  2. プラットフォームに依存するコードを使用して、子プロセスのリストと JVM プロセスの pid を取得します
  3. 新しいプロセスを生成する
  4. 子プロセス + pid の新しいリストを取得し、以前のリストと比較します。新しいのはあなたの男です。

子プロセスのみをチェックするため、同じマシン内の他のプロセスによって不当に扱われることはありません。JVM全体のミューテックスにより、新しいプロセスが正しいプロセスであることを確認できます。

子プロセス リストの読み取りは、Windows での WIN API 呼び出しを必要としないため、プロセス オブジェクトから PID を取得するよりも簡単であり、さらに重要なことに、いくつかのライブラリで既に行われています。

以下は、JavaSysMonライブラリを使用した上記のアイデアの実装です。これ

class UDKSpawner {

    private int uccPid;
    private Logger uccLog;

    /**
     * Mutex that forces only one child process to be spawned at a time. 
     * 
     */
    private static final Object spawnProcessMutex = new Object();

    /**
     * Spawns a new UDK process and sets {@link #uccPid} to it's PID. To work correctly,
     * the code relies on the fact that no other method in this JVM runs UDK processes and
     * that no method kills a process unless it acquires lock on spawnProcessMutex.
     * @param procBuilder
     * @return 
     */
    private Process spawnUDK(ProcessBuilder procBuilder) throws IOException {
        synchronized (spawnProcessMutex){            
            JavaSysMon monitor = new JavaSysMon();
            DirectUDKChildProcessVisitor beforeVisitor = new DirectUDKChildProcessVisitor();
            monitor.visitProcessTree(monitor.currentPid(), beforeVisitor);
            Set<Integer> alreadySpawnedProcesses = beforeVisitor.getUdkPids();

            Process proc = procBuilder.start();

            DirectUDKChildProcessVisitor afterVisitor = new DirectUDKChildProcessVisitor();
            monitor.visitProcessTree(monitor.currentPid(), afterVisitor);
            Set<Integer> newProcesses = afterVisitor.getUdkPids();

            newProcesses.removeAll(alreadySpawnedProcesses);

            if(newProcesses.isEmpty()){
                uccLog.severe("There is no new UKD PID.");
            }
            else if(newProcesses.size() > 1){
                uccLog.severe("Multiple new candidate UDK PIDs");
            } else {
                uccPid = newProcesses.iterator().next();
            }
            return proc;
        }
    }    

    private void killUDKByPID(){
        if(uccPid < 0){
            uccLog.severe("Cannot kill UCC by PID. PID not set.");
            return;
        }
        synchronized(spawnProcessMutex){
            JavaSysMon monitor = new JavaSysMon();
            monitor.killProcessTree(uccPid, false);
        }
    }

    private static class DirectUDKChildProcessVisitor implements ProcessVisitor {
        Set<Integer> udkPids = new HashSet<Integer>();

        @Override
        public boolean visit(OsProcess op, int i) {
            if(op.processInfo().getName().equals("UDK.exe")){
                udkPids.add(op.processInfo().getPid());
            }
            return false;
        }

        public Set<Integer> getUdkPids() {
            return udkPids;
        }
    }
}
于 2012-03-22T15:07:21.837 に答える
4

私のテストでは、すべての IMPL クラスに「pid」フィールドがありました。これは私のために働いています:

public static int getPid(Process process) {
    try {
        Class<?> cProcessImpl = process.getClass();
        Field fPid = cProcessImpl.getDeclaredField("pid");
        if (!fPid.isAccessible()) {
            fPid.setAccessible(true);
        }
        return fPid.getInt(process);
    } catch (Exception e) {
        return -1;
    }
}

戻り値が -1 でないことを確認してください。そうである場合は、 の出力を解析しますps

于 2015-04-01T23:30:56.717 に答える
2

Processオブジェクトから UNIX PID を取得するために、非常に簡単に追跡できる移植性のない方法を使用しました。

ステップ 1: いくつかの Reflection API 呼び出しを使用して、ターゲット サーバー JRE の実装クラスを識別します (これは抽象クラスであるProcessことを思い出してください)。Processあなたの UNIX 実装が私のものと似ている場合pid、プロセスの PID を含むという名前のプロパティを持つ実装クラスが表示されます。これが私が使用したロギングコードです。

    //--------------------------------------------------------------------
    // Jim Tough - 2014-11-04
    // This temporary Reflection code is used to log the name of the
    // class that implements the abstract Process class on the target
    // JRE, all of its 'Fields' (properties and methods) and the value
    // of each field.
    //
    // I only care about how this behaves on our UNIX servers, so I'll
    // deploy a snapshot release of this code to a QA server, run it once,
    // then check the logs.
    //
    // TODO Remove this logging code before building final release!
    final Class<?> clazz = process.getClass();
    logger.info("Concrete implementation of " + Process.class.getName() +
            " is: " + clazz.getName());
    // Array of all fields in this class, regardless of access level
    final Field[] allFields = clazz.getDeclaredFields();
    for (Field field : allFields) {
        field.setAccessible(true); // allows access to non-public fields
        Class<?> fieldClass = field.getType();
        StringBuilder sb = new StringBuilder(field.getName());
        sb.append(" | type: ");
        sb.append(fieldClass.getName());
        sb.append(" | value: [");
        Object fieldValue = null;
        try {
            fieldValue = field.get(process);
            sb.append(fieldValue);
            sb.append("]");
        } catch (Exception e) {
            logger.error("Unable to get value for [" +
                    field.getName() + "]", e);
        }
        logger.info(sb.toString());
    }
    //--------------------------------------------------------------------

ステップ 2: Reflection のログ記録から取得した実装クラスとフィールド名に基づいて、実装クラスをすり抜けるコードを記述Processし、Reflection API を使用して実装クラスから PID を取得します。以下のコードは、私の UNIX フレーバーで動作します。EXPECTED_IMPL_CLASS_NAMEおよびEXPECTED_PID_FIELD_NAME定数を調整して、機能させる必要がある場合があります。

/**
 * Get the process id (PID) associated with a {@code Process}
 * @param process {@code Process}, or null
 * @return Integer containing the PID of the process; null if the
 *  PID could not be retrieved or if a null parameter was supplied
 */
Integer retrievePID(final Process process) {
    if (process == null) {
        return null;
    }

    //--------------------------------------------------------------------
    // Jim Tough - 2014-11-04
    // NON PORTABLE CODE WARNING!
    // The code in this block works on the company UNIX servers, but may
    // not work on *any* UNIX server. Definitely will not work on any
    // Windows Server instances.
    final String EXPECTED_IMPL_CLASS_NAME = "java.lang.UNIXProcess";
    final String EXPECTED_PID_FIELD_NAME = "pid";
    final Class<? extends Process> processImplClass = process.getClass();
    if (processImplClass.getName().equals(EXPECTED_IMPL_CLASS_NAME)) {
        try {
            Field f = processImplClass.getDeclaredField(
                    EXPECTED_PID_FIELD_NAME);
            f.setAccessible(true); // allows access to non-public fields
            int pid = f.getInt(process);
            return pid;
        } catch (Exception e) {
            logger.warn("Unable to get PID", e);
        }
    } else {
        logger.warn(Process.class.getName() + " implementation was not " +
                EXPECTED_IMPL_CLASS_NAME + " - cannot retrieve PID" +
                " | actual type was: " + processImplClass.getName());
    }
    //--------------------------------------------------------------------

    return null; // If PID was not retrievable, just return null
}
于 2014-11-04T16:10:30.993 に答える
1

これは一般的な答えではありません。

ただし、一部のプログラム、特にサービスや長期実行プログラムは、「pid ファイル」を作成します (または、オプションで作成を提案します)。

たとえば、LibreOffice のオファーについては、ドキュメント--pidfile={file}を参照してください。

私は Java/Linux ソリューションをかなり探していましたが、(私の場合) PID は手元にありました。

于 2017-12-12T19:15:46.193 に答える
0

jnr-processプロジェクトはこの機能を提供します。

これは、jruby によって使用される Java ネイティブ ランタイムの一部であり、将来のJava-FFIのプロトタイプと見なすことができます。

于 2015-08-19T13:27:58.233 に答える
0

簡単な解決策はありません。私が過去に行った方法は、別のプロセスを開始してps、Unix ライクなシステムでコマンドを実行するか、 tasklistWindows でコマンドを実行し、そのコマンドの出力を解析して必要な PID を取得することでした。実際には、PID を返すプラットフォームごとに個別のシェル スクリプトにそのコードを入れることになりました。これにより、Java 部分を可能な限りプラットフォームに依存しないように保つことができました。これは短期間のタスクではうまく機能しませんが、私にとっては問題ではありませんでした。

于 2011-01-20T19:07:15.810 に答える