背景今天在运行一个定时任务的过程中,发现一个任务对数据集的查询时间范围出现了异常,并且开始时间戳高于结束时间戳。大怪现象,计算时间戳的代码大致如下。packagecom.lingyejun.authenticator;publicclassIntegerTest{publicstaticvoidmain(String[]args){longendTime=System.currentTimeMillis();longstartTime=endTime-30*24*60*60*1000;System.out.println("end:"+endTime);System.out。println("start:"+startTime);}}先放结论:因为java中整数默认是int类型,所以在计算过程中30*24*60*60*1000的计算结果大于Integer.MAX_VALUE,所以存在数据溢出,导致计算结果不准确的问题。验证我们对上面的代码稍作修改,方便我们确认定位问题。调整后的代码如下:packagecom.lingyejun.authenticator;publicclassIntegerTest{publicstaticlongcalcStartTime(longendTime,longminusMills){System.out.println("end:"+endTime+"minusmills:"+minusMills);longstartTime=endTime-minusMills;System.out.println("start:"+startTime);returnstartTime;}publicstaticvoidmain(String[]args){longnowTime=System.currentTimeMillis();longa=30*24*60*60*1000;calcStartTime(nowTime,a);}} 结果如下:end:1560869539864minusmills:-1702967296start:1562572507160这和我们预期的不一样,因为30*86400000=2592000000,但是计算出来是:-1702967296。说到这里,想必大家都知道原因了。这是因为java中整数的默认类型是int,int的最大值是2147483647,代码中java先计算右值,然后赋值给long变量。在计算右值(int类型乘法)时发生溢出,然后将溢出后截断的值赋值给变量,导致结果不准确。对代码做一个小改动,然后再看一下。packagecom.lingyejun.authenticator;publicclassIntegerTest{publicstaticlongcalcStartTime(longendTime,longminusMills){System.out.println("end:"+endTime+"minusmills:"+minusMills);longstartTime=endTime-minusMills;System.out.println("start:"+startTime);returnstartTime;}publicstaticvoidmain(String[]args){longnowTime=System.currentTimeMillis();longa=30*24*60*60*1000L;calcStartTime(nowTime,a);}}结果是end:1560869539864minusmills:2592000000start:1558277539864它看起来应该没有问题,但是真的安全吗?如果我要把30调整为24856(Integer.MAX_VALUE/86400=24855),也就是改成:longa=24856*24*60*60*1000L那么也会发生溢出。因为java的运算规则是从左到右,和最后一个long类型1000相乘前就溢出了,所以结果不对。正确的做法应该是:longa=24856L*24*60*60*1000。packagecom.lingyejun.authenticator;publicclassIntegerTest{publicstaticlongcalcStartTime(longendTime,longminusMills){System.out.println("end:"+endTime+"minusmills:"+minusMills);longstartTime=endTime-minusMills;System.out.println("开始:"+startTime);returnstartTime;}publicstaticvoidmain(String[]args){longa=30L*24*60*60*1000;calcStartTime(nowTime,a);}}
