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

2024-02-11

我们遇到这样的情况:主进程写入日志。

然后它会生成多个工作进程,这些进程会写入自己的日志。 (我希望工作人员通过主服务器登录,但由于某种原因,这个想法遭到了抵制。)

我想知道的是,我可以相信多个文件中最终的时间戳彼此一致吗?即,如果我将日志文件合并为按即时排序的单个文件,事件的顺序是否正确?跨越所有可能的操作系统?

我问这个问题的原因是我遇到了一种奇怪的情况,在主进程报告工作进程有错误后两秒,工作进程似乎记录了错误。就好像大师能够看到未来一样。 (我猜主人也是时间领主,但是呃……)


致电给System.currentTimeMillis https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/System.html#currentTimeMillis(),及其现代替代品Instant.now,两者都捕获主机操作系统和底层计算机时钟硬件报告的当前时刻。 Javadoc 和源代码承诺“基于最佳可用系统时钟”的时钟。

所以,不,应该有不跳进未来。每次调用这些方法中的任何一个时,您都会捕获当前时刻。

但是,您可能会看到跳跃到未来的幻觉。发生这种情况的原因可能如下:

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

线程调度

这种错觉可能会因为发生的事情而出现after当前时刻被捕获。捕获当前时刻后的瞬间,该线程的执行可能会暂停。然后,其他一些线程可能会捕获稍后的时刻,并继续报告该时刻。最终,第一个线程恢复,并报告其先前捕获的时刻 - 但请注意报告那一刻的事情发生在稍后。

以这个示例代码为例。

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 行。第 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他们的执行被推迟了,所以一些早期的时刻后来才被报道。同样,我怀疑在您的情况下,记录捕获时刻的行为涉及各种延迟,因此一些较早的时刻被稍后记录。

时钟重置

As 斯蒂芬·C https://stackoverflow.com/users/139985/stephen-c指出在下面的评论中 https://stackoverflow.com/questions/64961179/is-system-currenttimemillis-correct-across-multiple-processes/64961281#comment114847421_64961281,计算机通常配置为根据时间服务器的信息自动调整硬件时钟。许多计算机中的硬件时钟没有您想象的那么准确。因此,主机的时钟很可能会重置为一天中较早或较晚的时间,以纠正时间跟踪漂移。

请注意,某些计算机会将时钟重置为时代参考 https://en.wikipedia.org/wiki/Epoch_(computing)当使用支持硬件时钟的有故障或耗尽的电池/电容器启动时,例如 1970-01-01 00:00Z 等点。该纪元参考时刻可以被报告为当前时刻,直到计算机有机会与时间服务器核对。

或者有人可以手动调整计算机时钟的当前日期和时间。 :-(

您的代码可能会捕获此时钟调整两侧的当前时刻。现在,后来发生的事件可能看起来更早发生。

假时钟

In java.time,调用诸如Instant.now访问当前分配的Clock https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/time/Clock.html执行。我所说的“当前分配”是指以下事实:java.time,默认Clock对象可以被覆盖。通常这仅用于测试目的。各种各样的Clock对象可以报告固定时刻 https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/time/Clock.html#fixed(java.time.Instant,java.time.ZoneId), 一个转移的时刻 https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/time/Clock.html#offset(java.time.Clock,java.time.Duration),或者可以报告改变的节奏 https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/time/Clock.html#tick(java.time.Clock,java.time.Duration).

所以请注意,替代方案Clock如果您的测试代码指定了替代时间,则可能会故意告知不同的时间Clock目的。默认情况下,您始终会在执行方法调用时获取当前时刻。

结论

这里有一个重要的含义:时间追踪不能完全可信。当前时刻可能是错误捕获,以及报告捕获的瞬间可能是无序的。

因此,在调试或调查时,请始终牢记这一想法:时间戳及其顺序may不会告诉你全部真相。你最终无法 100% 确定何时发生了什么。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

`System.currentTimeMillis()` 在多个进程中是否正确? 的相关文章

随机推荐

  • 使用 PHP 从 Microsoft Teams 自定义机器人验证 HMAC

    我正在尝试使用 PHP 验证 Microsoft Teams 自定义机器人 遵循 Microsoft指示 https learn microsoft com en us microsoftteams platform concepts cu
  • CUDA 确定每个块的线程、每个网格的块

    我是 CUDA 范式的新手 我的问题是确定每个块的线程数和每个网格的块数 这是否需要一些艺术和尝试 我发现许多例子似乎为这些事情选择了任意的数字 我正在考虑一个问题 我可以将任意大小的矩阵传递给乘法方法 这样 C 的每个元素 如 C A B
  • Java 8 中流的笛卡尔积作为流(仅使用流)

    我想创建一种方法 该方法创建一个元素流 这些元素是多个给定流的笛卡尔积 最后由二元运算符聚合为相同类型 请注意 参数和结果都是流 not收藏 例如 对于两个流 A B and X Y 我希望它产生价值流 AX AY BX BY 简单的串联用
  • Docx4j 字符串中的换行符

    我有这个字符串 Prueba Lista li1 li2 li3 li4 Tabulado Tabulado Tabulado Tabulado Tabulado Tabulado Tabulado Tabulado Tabulado Ta
  • dplyr 中的 substr %>% mutate

    pcd lt data frame tripNo c 618 618 610 610 610 619 procDate as Date c 2016 03 02 2016 03 03 2016 03 02 2016 03 03 2016 0
  • 手动调用按钮上的 click() ,我可以传递任何参数吗?

    我在 jquery javascript 代码中手动调用页面上的按钮上的 click 我需要传递一个参数来单击 然后我可以在响应单击事件的函数上读取该参数 这可能吗 你需要调用 trigger 您可以在那里传递任意数量的参数 element
  • 将尾部输出通过管道传输到另一个脚本中

    我正在尝试将 tail 命令的输出通过管道传输到另一个 bash 脚本中进行处理 tail n 1 f your log file myscript sh 但是 当我运行它时 永远不会到达 1 参数 在 myscript sh 内 我缺少什
  • ORA-38104: ON 子句中引用的列无法更新

    我有一个带有删除标志的简单表 记录应在此列中更新而不是删除 create table PSEUDODELETETABLE ID NUMBER 8 not null PKEY NAME VARCHAR2 50 not null ISDELET
  • 为订阅优惠生成签名 - Xcode - Swift

    我想问是否有人已经实现了 inapp 订阅 自动续订 的新优惠 如果可能的话 在服务器端创建系统以使用 p8 密钥和 php 创建此签名的难度 我在苹果文档中找到了这个 我不确定是否理解它 https developer apple com
  • Jquery 无法检测 IE 11

    刚刚偶然发现一个问题 当尝试使用 Jquery 检测 IE 11 当前正在播出的测试版 时 结果是 firefox 相同的代码检测 IE 10 我需要知道用户正在使用什么浏览器才能显示不同的指令 我正在 Oracle VirtualBox
  • Spark DataFrame 架构可为空字段

    我在 Scala 和 Python 中编写了以下代码 但是返回的 DataFrame 似乎没有应用我正在应用的架构中的非空字段 italianVotes csv是一个 csv 文件 以 作为分隔符和四个字段 我正在使用火花2 1 0 意大利
  • 在多索引数据框中选择行

    我想单独提取 S 的 bin 其中每列 X Y gt 0 5 或多个 bin gt 0 5 行数 在示例中 对于 AR1 应仅选择 bin 4 因为 X 和 Y gt 0 5 蓝色指示 对于 PO1 应选择 bin 1 2 3 和 4 因为
  • 如何在 win7 x64 上使用带有 php (xampp) 的 oracle 客户端 11.2

    我刚刚在我的 win7 x64 PC 上安装了一个实际的 XAMPP 来编写一些 PHP 脚本来连接到 Oracle DB 我还安装了正常的oracle 11 2 0客户端 PATH和ORACLE HOME设置正确 该客户端用于我的所有其他
  • android 如何将对象保存到文件?

    有人知道如何在 android 上将对象保存和恢复到文件吗 使用 openFileOutput 打开文件 http developer android com guide topics data data storage html file
  • 页面重新加载后,Meteor.user() 返回未定义

    问题是我想检查用户是否通过我的路线中的 onBeforeAction 内的 Meteor user 登录 问题是 页面重新加载后 Meteor user 在加载之前的一瞬间返回未定义 这是我的路线配置 Router map function
  • 设置 dbt 日期变量

    我试图将 dbt 模型中的日期变量设置为 7 天前的日期 该模型将针对 Redshift 数据库运行 我已执行以下操作来设置变量 但是收到错误 DATE ADD 未定义 set start date TRUNC DATE ADD day 7
  • python pycparser设置错误

    我在 CentOS 7 上通过 pip 设置 pyparser 时看到以下错误 usr bin python2 u c import setuptools tokenize file tmp pip build PMzCYU pycpars
  • GMSAutocompleteViewController iOS,如何更改搜索栏中的文本颜色[重复]

    这个问题在这里已经有答案了 我正在使用 GMSAutocompleteViewController 并想要更改 searchBar 中的 textColor 但找不到方法 我设法更改了一些颜色但没有更改 searchBar 文本 我尝试过以
  • hostconfig.json 在哪里(Docker 桌面 + WSL2 环境)

    据我所知 docker不支持任何在创建容器后更改端口映射的命令 但这个答案说 通过更改 hostconfig json 文件 我可以更改端口映射 如何将端口映射分配给现有的 Docker 容器 https stackoverflow com
  • `System.currentTimeMillis()` 在多个进程中是否正确?

    我们遇到这样的情况 主进程写入日志 然后它会生成多个工作进程 这些进程会写入自己的日志 我希望工作人员通过主服务器登录 但由于某种原因 这个想法遭到了抵制 我想知道的是 我可以相信多个文件中最终的时间戳彼此一致吗 即 如果我将日志文件合并为