ProcessHandle возвращает неоднозначные результаты

#java #linux #pid #isalive #processhandle

Вопрос:

У меня есть два метода Java 11, которые проверяют, запущен ли процесс для данного PID:

   public static final boolean isProcessRunning( final long pid ) {
    Optional< ProcessHandle > optionalProcess = ProcessHandle.of( pid );
    return optionalProcess.isPresent() amp;amp; optionalProcess.get().isAlive();
  }

  public static boolean isProcessRunning2( final long pid ) {
    return ProcessHandle.allProcesses()
        .filter( p -> p.pid() == pid )
        .anyMatch( p -> p.isAlive() );
  }
 

При проверке нескольких PID на клиентах Linux я иногда получаю разные результаты для определенных PID, где первая реализация всегда возвращается true , а вторая всегда false .

Проверка некоторых «ложных срабатываний» с помощью команды оболочки ps -ef | grep <pid> показывает, что первая реализация кажется неправильной, ОС также не знает об этих процессах. Предположительно, вторая реализация всегда верна, но кажется очень неэффективной.

Что не так с первой реализацией и как я могу это исправить?

Ответ №1:

Взглянув на реализацию ProcessHandleImpl.isAlive() (версия Java 11), кажется, что этот метод может вернуться true , если собственный метод isAlive0(pid) возвращает 0, что он и делает, «если время начала не может быть определено». Тот же собственный метод также используется для определения того, следует ли возвращать пустое необязательное значение (возвращает -1) или нет (возвращает 0 или фактическое время начала). ProcessHandle.allProcesses() с другой стороны, получает все дочерние значения pid 0, а затем вызывает getProcessPids0(...) (другой собственный метод), чтобы вернуть pid и время начала.

Таким образом, похоже, что это разница в машинном коде используемой вами JVM — или в вашей операционной системе (зависит от того, что делает машинный код).

Чтобы «исправить» свой первый фрагмент, вы можете исключить время начала «0» с помощью info().startInstant().isPresent() :

 public static final boolean isProcessRunning( final long pid, final boolean excludeUnsure ) {
    Optional< ProcessHandle > optionalProcess = ProcessHandle.of( pid );
    
    if( excludeUnsure ) {
        return optionalProcess.map(ph -> ph.info())
                .flatMap(info -> info.startInstant())
                .isPresent();
    } else {
        return optionalProcess.map(ph -> ph.isAlive()).orElse(Boolean.FALSE);
    }      
 }