致电给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% 确定何时发生了什么。