Правильно ли System.currentTimeMillis () для нескольких процессов?

У нас есть ситуация, когда главный процесс записывает в журнал.

Затем он порождает несколько рабочих процессов, которые записывают в свои собственные журналы. (Я хотел, чтобы рабочие входили в систему через мастер, но по какой-то причине эта идея встретила сопротивление.)

Я хочу знать, могу ли я быть уверен в том, что временные метки в нескольких файлах согласованы друг с другом? то есть, если я объединю файлы журнала в один файл, отсортированный по мгновению, будет ли порядок событий истинным? Во всех возможных операционных системах?

Причина, по которой я спрашиваю об этом, заключается в том, что у меня странная ситуация, когда кажется, что рабочий процесс зарегистрировал ошибку через две секунды после того, как мастер сообщил, что у рабочего возникла ошибка. Как будто мастер умел заглядывать в будущее. (Думаю, хозяин тоже повелитель времени, но ...)


person Trejkaz    schedule 23.11.2020    source источник
comment
Эта функция основана на системном времени и даже не гарантирует ее монотонность в одном процессе. См. этот пост   -  person that other guy    schedule 23.11.2020
comment
Ответ Бэзила Бурка абсолютно правильный: пожалуйста, проголосуйте и примите его. TL; DR: 1) currentTimeMillis () - это то, что сообщает система. Это верно; он будет таким же в этот момент для любого процесса / любой задачи, которая его читает. 2) ОДНАКО: нет никакой гарантии, что задача или процесс будет ПЛАНИРОВАТЬ для их чтения. Также нет никакой гарантии, что разные задачи / процессы будут запланированы в определенном порядке по отношению друг к другу. 3) Если вы используете log4j2, эта статья может вас заинтересовать: logging.apache.org/log4j/2.x/manual/async.html   -  person paulsm4    schedule 23.11.2020


Ответы (1)


Вызов _ 1_ и его современная замена Instant.now фиксируют текущий момент, сообщаемый ОС хоста и базовым оборудованием часов компьютера. Документ Javadoc и исходный код обещают часы, «основанные на наилучших доступных системных часах».

Итак, нет, нельзя прыгать в будущее. Каждый раз, когда вы вызываете любой из этих методов, вы фиксируете текущий момент.

Однако вы можете увидеть иллюзию прыжка в будущее. Это может произойти по следующим причинам:

  • планирование потоков
  • сброс часов
  • поддельные часы

Планирование потоков

Эта иллюзия может возникнуть из-за того, что происходит после захвата текущего момента. Через долю секунды после захвата текущего момента выполнение этого потока может быть приостановлено. Другой поток может затем захватить более поздний момент и продолжить сообщать об этом моменте. В конце концов, этот первый поток возобновляется и сообщает о своем ранее зафиксированном моменте, но обратите внимание, как сообщение об этом моменте происходит позже.

Возьмите этот пример кода.

package work.basil.example;

import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TellTime
{
    public static void main ( String[] args )
    {
        TellTime app = new TellTime();
        app.demo();
    }

    private void demo ( )
    {
        ExecutorService executorService = Executors.newCachedThreadPool();

        int countThreads = 15;
        List < Callable < Object > > tasks = new ArrayList <>( countThreads );
        for ( int i = 0 ; i < countThreads ; i++ )
        {
            Runnable tellTimeRunnable = ( ) -> System.out.println( Instant.now() );
            tasks.add( Executors.callable( tellTimeRunnable ) );
        }
        try
        {
            List < Future < Object > > list = executorService.invokeAll( tasks );
        }
        catch ( InterruptedException e )
        {
            e.printStackTrace();
        }
    }
}

В самый первый раз, когда я запустил этот код, я обнаружил такой скачок в последних двух строках вывода. 4-я строка показывает момент раньше, чем 3-я. Пятая строка показывает момент даже раньше.

2020-11-23T01:07:34.305318Z
2020-11-23T01:07:34.305569Z
2020-11-23T01:07:34.305770Z
2020-11-23T01:07:34.305746Z
2020-11-23T01:07:34.305434Z

В моем случае вызовы System.out.println задерживались в выполнении, поэтому о некоторых более ранних моментах сообщалось позже. Точно так же я подозреваю, что в вашем случае процесс регистрации ваших захваченных моментов включал в себя различные задержки, так что некоторые более ранние моменты были зарегистрированы позже.

Сброс часов

Как указывает Стивен С в комментариях ниже компьютеры часто настраиваются на автоматическую настройку аппаратных часов на основе информации с сервера времени. Аппаратные часы на многих компьютерах менее точны, чем вы можете себе представить. Таким образом, часы главного компьютера вполне могут быть сброшены на более раннее или более позднее время дня, чтобы скорректировать дрейф отслеживания времени.

Имейте в виду, что некоторые компьютеры сбрасывают свои часы обратно к точке эталонной эпохи, например 1970 г. -01-01 00: 00Z при загрузке с неисправным или разряженным аккумулятором / конденсатором, поддерживающим аппаратные часы. Этот эталонный момент эпохи может указываться как текущий момент, пока компьютер не получит возможность связаться с сервером времени.

Или какой-нибудь человек может вручную настроить текущую дату и время на компьютерных часах. :-(

Ваш код может фиксировать текущий момент по обе стороны от этой настройки часов. Теперь может показаться, что более позднее событие произошло раньше.

Поддельные часы

В java.time такие вызовы, как Instant.now, обращаются к назначенному в данный момент _ 7_ реализация. Под текущим назначением я обращаюсь к тому факту, что в java.time объект Clock по умолчанию может быть переопределен. Обычно это делается только для целей тестирования. Различные объекты Clock могут сообщать фиксированный момент, сдвинутый момент или может сообщить с измененный ритм.

Так что имейте в виду, что альтернативный Clock может намеренно указать другое время, если в вашем тестовом коде указан альтернативный Clock объект. По умолчанию вы всегда получаете текущий момент времени выполнения вызова метода.

Вывод

Здесь есть важный вывод: нельзя полностью доверять учету времени. Текущий момент может быть неправильно записан, и отчет о захваченных моментах может быть неупорядоченным.

Поэтому при отладке или исследовании всегда держите эту мысль в глубине души: временные метки и их порядок могут не сказать вам всю правду. В конечном итоге вы не можете знать со 100% уверенностью, что и когда произошло.

person Basil Bourque    schedule 23.11.2020
comment
Очередной шедевр! - person Arvind Kumar Avinash; 24.11.2020