java - `System.currentTimeMillis()`在多个进程中是否正确?

标签 java time system-clock

我们有一个主进程写入日志的情况。
然后,它产生多个写入其自己的日志的工作进程。 (我希望工作人员可以通过管理员进行登录,但是由于某种原因,对此想法产生了抵制。)
我想知道的是,我是否可以相信以多个文件结尾的时间戳彼此一致?即,如果我将日志文件按即时合并到单个文件中,事件的顺序是否正确?在所有可能的操作系统上?
我问这个问题的原因是我有一个奇怪的情况,在主服务器报告该工作程序有错误后两秒钟,似乎一个工作进程记录了一个错误。就像大师能够看到 future 一样。 (我想主人也是一位时间贵族,但是...)

最佳答案

System.currentTimeMillis 的调用及其现代替换Instant.now都捕获了主机操作系统和底层计算机时钟硬件报告的当前时刻。 Javadoc和源代码 promise “基于最佳可用系统时钟”提供时钟。
因此,不应该,没有不能进入 future 的。每次调用这些方法中的任何一个,都将捕获当前时刻。
但是,您可能会看到跳入 future 的幻想。由于以下原因,可能会发生这种情况:

  • 线程调度
  • 时钟重置
  • 假时钟

  • 线程调度
    这种错觉可能是由于捕获当前时刻之后发生的事情而发生的。捕获当前时刻后的瞬间,该线程的执行可能会暂停。然后,其他某个线程可能会捕获一个较晚的时刻,并继续报告该时刻。最终,第一个线程恢复运行,并报告其较早捕获的时刻-但请注意该时刻的报告是如何在以后发生的。
    以这个示例代码为例。
    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();
            }
        }
    }
    
    我第一次运行该代码时,在输出的后两行中发现了这种跳跃。第四行显示的时间早于第三行。第5行显示的时间更早。
    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的调用在执行上被延迟,因此稍后会报告一些较早的时刻。同样,我怀疑在您的情况下,记录捕获的时刻的行为涉及各种延迟,因此一些较早的时刻会在以后记录。
    时钟重置
    正如Stephen C指出in comments below一样,计算机通常被配置为根据来自时间服务器的信息自动调整硬件时钟。许多计算机中的硬件时钟都不如您想象的准确。因此,主机计算机的时钟很可能会重置为较早或较晚的时间,以纠正时间跟踪偏差。
    请注意,某些计算机在故障/耗尽的电池/电容器支持硬件时钟的情况下启动时,会将其时钟重设回epoch reference点,例如1970-01-01 00:00Z。该纪元引用时刻可以被报告为当前时刻,直到计算机有机会与时间服务器 checkin 。
    或者某些人可以手动调整计算机时钟的当前日期和时间。 :-(
    您的代码可能会在此时钟调整的任何一侧捕获当前时刻。现在,似乎较早发生了以后的事件。
    假时钟
    在java.time中,诸如Instant.now的调用访问当前分配的 Clock 实现。通过“当前分配”,我指的是在java.time中可以覆盖默认的Clock对象的事实。通常,这仅用于测试目的。各种Clock对象可以报告a fixed momenta shifted moment,也可以报告an altered cadence
    因此请注意,如果您的测试代码指定了备用Clock对象,则备用Clock可能会故意告诉其他时间。默认情况下,尽管总是在执行方法调用时获得当前时刻。
    结论
    这里有一个主要含义:无法完全信任时间跟踪。当前时刻可能被错误地捕获,并且捕获时刻的报告可能是乱序的。
    因此,在进行调试或调查时,请始终将这种想法隐藏在脑海中:时间戳记及其排序可能并不能告诉您全部真相。您最终无法100%地确定何时会发生什么。

    关于java - `System.currentTimeMillis()`在多个进程中是否正确?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64961179/

    相关文章:

    java - 获取 24 小时制的当前时间和日期

    amazon-web-services - 在使用 Amazon 的 EC2 服务来对抗时钟漂移时,我应该使用 NTP 服务器吗?

    java - 需要帮助创建 hbm.xml

    java - 在 Spring Boot 中将 Apache Mahout 与 ElasticSearch 集成

    java - 嵌套 Json 以使用 Jackson 映射

    c# - 多系统时钟

    algorithm - Lamport同步算法讨论中的 "partial ordering"和 "total ordering"是什么意思?

    java - 为邪恶的刽子手程序存储数据

    java - 计算持续时间

    java - Java中数组寻址的时间复杂度差异