system.currenttimemillis()`跨多个进程是否正确?

g9icjywg  于 2021-07-08  发布在  Java
关注(0)|答案(1)|浏览(215)

在这种情况下,主进程会写入日志。
然后,它生成多个工作进程,这些进程写入自己的日志(我想让工人们通过主机登录,但由于某种原因,这个想法遭到了抵制。)
我想知道的是,我能相信最终出现在多个文件中的时间戳是一致的吗?i、 例如,如果我将日志文件合并到一个按即时排序的文件中,事件的顺序会是真的吗?跨所有可能的操作系统?
我问这个问题的原因是我遇到了一个奇怪的情况,在主进程报告工作进程有错误的两秒钟后,工作进程似乎记录了一个错误。就像主人能预见未来一样(我猜主人也是时间领主,但是……)

yv5phkfx

yv5phkfx1#

呼叫 System.currentTimeMillis ,以及它的现代替代品 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();
        }
    }
}

第一次运行代码时,我发现最后两行输出中出现了这样的跳转。第四行显示的时间比第三行早。第五行显示的时间甚至更早。

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在下面的评论中指出的,计算机通常被配置为根据时间服务器的信息自动调整硬件时钟。许多计算机的硬件时钟没有你想象的那么精确。因此,主机的时钟很可能会重置为一天中较早或较晚的时间,以纠正时间跟踪漂移。
请注意,某些计算机在启动时,如果有故障或耗尽的电池/电容器支持硬件时钟,则会将时钟重置回一个历元参考点,例如1970-01-01 00:00z。该历元参考时刻可以被报告为当前时刻,直到计算机有机会向时间服务器报到。
或者一些人可以手动调整电脑时钟的当前日期和时间-(
您的代码可能会捕获此时钟调整两侧的当前时刻。现在,一个后来的事件似乎发生得更早。

假钟

在java.time中,调用 Instant.now 访问当前分配的 Clock 实施。通过“currently assigned”,我指的是在java.time中 Clock 对象可以被重写。通常这只是为了测试目的。各种各样的 Clock 对象可以报告一个固定的时刻,一个移动的时刻,也可以报告一个改变的节奏。
所以要注意 Clock 如果您的测试代码指定了一个替代的 Clock 对象。默认情况下,尽管您总是在方法调用执行时获取当前时刻。

结论

这里有一个重要的含义:时间跟踪不能完全可信。当前时刻可能捕捉不正确,捕捉时刻的报告可能不正常。
因此,在调试或调查时,一定要把这个想法藏在脑后:时间戳和它们的顺序可能不会告诉你全部真相。你最终无法百分之百肯定地知道什么时候发生了什么。

相关问题