当前毫秒,从 long 到 int

Current milliseconds, from long to int

提问人:Luchian Grigore 提问时间:11/23/2011 最后编辑:Luchian Grigore 更新时间:11/24/2011 访问量:25346

问:

我目前有以下代码:

public static int currentTimeMillis()
{
    long millisLong = System.currentTimeMillis();
    while ( millisLong > Integer.MAX_VALUE )
    {
        millisLong -= Integer.MAX_VALUE;
    }
    return (int)millisLong;
}

它以某种格式返回当前时间(不完全是,但可用于时差)。出于很好的理由,我不能使用 .intlong

是的,我只是对两个调用之间的区别感兴趣,这种方法效果很好。但它看起来不对劲。我知道那件事。而且效率低下。我知道。所以我的问题是,我该如何改进它?

我需要一个函数,该函数返回:int

int x1 = currentTimeMillis(); //my function
long y1 = System.currentTimeMillis();

.....

int x2 = currentTimeMillis();
long y2 = System.currentTimeMillis();

// here, x2 - x1 must be equal to y2 - y1

编辑:

仅供参考,我想这样做进行基准测试。我正在多个线程上并行运行测试,停止事件由外部组件触发。我还以仅支持 的方式序列化数据,并且我正在序列化的对象不能有成员。intlong

爪哇岛

评论

0赞 Dave 11/23/2011
知道你为什么要这样做会很有帮助。你已经给了我们你想要的东西,并要求如何去做,但没有上下文,我只是想“为什么?
0赞 Luchian Grigore 11/23/2011
@Dave我提供了一个总结性的解释。

答:

31赞 BalusC 11/23/2011 #1

您的函数与以下功能基本相同:

public static int currentTimeMillis() {
    return (int) (System.currentTimeMillis() % Integer.MAX_VALUE);
}

以上可能就是你要找的。模运算符返回除法的余数。我只会把它包装在另一个隐藏起来的类中。也就是说,将“当前时间(以毫为单位)”作为具有错误值的 int 会造成混淆。像这样:%

Stopwatch stopwatch = Stopwatch.start();

// ...

int elapsed = stopwatch.elapsed();

public final class Stopwatch {

    private long start;

    private Stopwatch() {
        start = System.currentTimeMillis();
    }

    public static Stopwatch start() {
        return new Stopwatch();
    }

    public int elapsed() {
        return (int) (System.currentTimeMillis() - start);
    }

}

这也更好,以防止在开始时间小于而结束时间大于时出现问题,从而溢出回并继续从那里继续。Integer.MAX_VALUEInteger.MAX_VALUEInteger.MIN_VALUE

评论

0赞 bezmax 11/23/2011
我想补充一点,如果你要为此创建一个单独的类,并且只需要时间上的差异,那么你可能应该节省时间,但在需要时返回差异,以确保你不会在任何地方得到整数溢出。longint
0赞 BalusC 11/23/2011
@Max:与此同时,我用一个具体的例子更新了答案。
0赞 bezmax 11/23/2011
我明白了,我的评论陷入了严重的交通拥堵。
0赞 Luchian Grigore 11/23/2011
第一种选择是完美的。我觉得不去想它很愚蠢,我想有时你只是需要对事物有一个新的看法。我不能使用第二个,因为......井。。。停止是由一些事件触发的,多个线程并行运行......谢谢。
0赞 Peter Lawrey 11/23/2011
每 24 天溢出一次,此时差异将不正确。
2赞 Asaph 11/23/2011 #2

您将无法 100% 满足您的条件,因为在执行过程中程序中的行之间可能会经过时间,这会稍微偏离情况。但这些数字不会有太大的差异。在不了解您的问题的情况下,我不得不假设您对实际时间不感兴趣。也许你只是对经过的时间感兴趣?您是否正在运行一些基准测试?如果您只需要经过的时间,@BalusC建议的模量解就可以了。

评论

0赞 Luchian Grigore 11/23/2011
同意,但时间不太可能重叠。
3赞 bezmax 11/23/2011 #3

与其找到模数,不如使用简单的按位掩码操作:

public static int currentTimeMillis() {
    return (int) (System.currentTimeMillis() & 0x00000000FFFFFFFFL);
}

评论

3赞 StriplingWarrior 11/23/2011
您是否有基准测试表明此解决方案会“快得多”?
0赞 bezmax 11/23/2011
@StriplingWarrior有趣的是,我 100% 确定模数很慢,但我忘记了编译器优化。en.wikipedia.org/wiki/Modulo_operation#Performance_issues 指出,可以使用按位 AND 运算来优化数字的模数。这基本上就是我所做的。好吧,我想 Java 编译器的工作量更少:Ppower of 2
4赞 jarnbjo 11/23/2011
确定!在我的计算机上,&运算符比模计算快1.25ns。这应该至少是 3 或 4 个 CPU 周期。如果你能进行如此大规模的优化,谁会在乎代码的可读性?(如果你发现讽刺,你可以保留它)。
0赞 StriplingWarrior 11/24/2011
@jarnbjo:我沉浸在讽刺中。:-D
3赞 StriplingWarrior 11/23/2011 #4

请注意,如果该值在 take 和 之间滚动,则最终将得到负值。有两种方法可以解决这个问题。currentTimeMillisInteger.MAX_VALUEx1x2x2 - x1

  1. 使用 BalusC 的方法,然后在减去时检查它是否为负数。如果是,请再次添加。(这假设不会检查两个实际上相距超过距离的时间值。x2 - x1Integer.MAX_VALUEInteger.MAX_VALUE
  2. 首次初始化类时,将当前时间存储为私有静态值。从那时起,使函数返回当前时间与第一次启动时间之间的差值。这假定这些时间值在系统重新启动时不需要保留,并且系统不会处于足够长的生存状态而无法通过标记。Integer.MAX_VALUE

顺便说一句,我相信我们都想知道你不使用值的充分理由是什么?long

2赞 Peter Lawrey 11/23/2011 #5

你可以做

public static int currentTimeMillis() {
    return (int) System.currentTimeMillis();
}

如果它是负面的,只要你有所作为,那就没关系了。例如

int start = currentTimeMillis();

// will be positive for differences less than 24 days.
int time = currentTimeMillis() - start; 

使用这种方法可以避免溢出问题,因为它们会抵消,例如

int start = Integer.MAX_VALUE;
// 1 ms later
int time = Integer.MIN_VALUE /*due to overflow*/ - start; 
// time equals 1 due to underflow.