Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/385.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java DateFormat或Calendar.getInstance有时返回随机值_Java_Android_Multithreading_Time_Thread Safety - Fatal编程技术网

Java DateFormat或Calendar.getInstance有时返回随机值

Java DateFormat或Calendar.getInstance有时返回随机值,java,android,multithreading,time,thread-safety,Java,Android,Multithreading,Time,Thread Safety,下面的now()代码对一个对象执行两次。一次表示它的创建,另一次表示它何时写入数据库 在一个受控测试中,我成功地重现了一个日期相差很大的bug。有些日期似乎有正确的日期,但在00:00:00或接近00:00:00 另一些人似乎相对落后几个小时,从1小时到16小时甚至几周不等。我还设定了未来的时间Calendar.getInstance.getTime()应该等同于System.getCurrentTimeMillis(),让后者偶尔返回一个未来时间是令人担忧的 我没有发现任何东西,我将进一步调查

下面的
now()
代码对一个对象执行两次。一次表示它的创建,另一次表示它何时写入数据库

在一个受控测试中,我成功地重现了一个日期相差很大的bug。有些日期似乎有正确的日期,但在
00:00:00
或接近
00:00:00

另一些人似乎相对落后几个小时,从1小时到16小时甚至几周不等。我还设定了未来的时间
Calendar.getInstance.getTime()
应该等同于
System.getCurrentTimeMillis()
,让后者偶尔返回一个未来时间是令人担忧的

我没有发现任何东西,我将进一步调查这个问题,并在这里报告我的发现

private static DateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");

public static String calendarToDb(Calendar cal) {
    if (cal == null) {
        return null;
    }
    return simpleDateFormat.format(cal.getTime());
}

public static String now() {
    return calendarToDb(Calendar.getInstance());
}
以下是android监视器日志的相关部分。这是一个真实的设备,不是模拟器。M代表MessageManager,P代表ContentProvider

08-30 18:07:17.267 M: main             starttime  = 2016-01-01T00:07:00+0100\
08-30 18:07:17.306 P: AsyncQueryWorker CreateTime = 2016-08-30T18:07:17+0200\
08-30 18:07:18.326 M: main             starttime  = 2016-01-01T00:00:00+0200\
08-30 18:07:18.371 P: AsyncQueryWorker CreateTime = 2016-08-30T18:07:18+0200\
08-30 18:07:19.898 M: main             starttime  = 2016-08-30T18:07:19+0200\
08-30 18:07:19.920 P: AsyncQueryWorker CreateTime = 2016-08-30T00:00:00+0100\

我的数据库中有更多看起来更奇怪的数据,根本不应该发生。

问题似乎最有可能在于静态数据

static DateFormat simpleDateFormat
如下文所述:

如果多个线程使用同一实例(由于静态原因,它们会这样做),则会存储中间结果。时间可以在方法执行期间部分重置,这会使当前处理的结果发生偏差


解决方案是每次返回新实例。

问题似乎最有可能在于静态

static DateFormat simpleDateFormat
如下文所述:

如果多个线程使用同一实例(由于静态原因,它们会这样做),则会存储中间结果。时间可以在方法执行期间部分重置,这会使当前处理的结果发生偏差

解决方案是每次返回新实例。

避免遗留日期时间类 这是正确的,应该被接受。您可能会看到由于旧日期时间类中缺乏线程安全性而导致的错误。这是避免这些麻烦的旧遗留日期时间类的许多原因之一

相反,您应该使用这些类。time类具有线程安全性

ISO 8601 您的输入字符串恰好符合日期时间格式的标准

在解析/生成字符串时,java.time类默认使用ISO 8601格式。因此,您不需要指定格式化模式,而需要针对当前Java8实现中的错误进行指定。当前,UTC偏移量中缺少冒号会导致默认情况下解析失败。应该在Java9中修复。而在Java8中,使用and指定模式

OffsetDateTime
输入字符串表示与UTC的偏移,但不是完整时区。所以我们将其解析为对象

在Java 9及更高版本中,直接解析:

OffsetDateTime odt = OffsetDateTime.parse ( input );
在Java8中,使用上面构建的
DateTimeFormatter
对象

OffsetDateTime odt = OffsetDateTime.parse ( input , f );
转储到控制台

System.out.println ( "input: " + input + " | odt: " + odt );
输入:2016-08-30T18:07:17+0200 | odt:2016-08-30T18:07:17+02:00

避免遗留日期时间类 这是正确的,应该被接受。您可能会看到由于旧日期时间类中缺乏线程安全性而导致的错误。这是避免这些麻烦的旧遗留日期时间类的许多原因之一

相反,您应该使用这些类。time类具有线程安全性

ISO 8601 您的输入字符串恰好符合日期时间格式的标准

在解析/生成字符串时,java.time类默认使用ISO 8601格式。因此,您不需要指定格式化模式,而需要针对当前Java8实现中的错误进行指定。当前,UTC偏移量中缺少冒号会导致默认情况下解析失败。应该在Java9中修复。而在Java8中,使用and指定模式

OffsetDateTime
输入字符串表示与UTC的偏移,但不是完整时区。所以我们将其解析为对象

在Java 9及更高版本中,直接解析:

OffsetDateTime odt = OffsetDateTime.parse ( input );
在Java8中,使用上面构建的
DateTimeFormatter
对象

OffsetDateTime odt = OffsetDateTime.parse ( input , f );
转储到控制台

System.out.println ( "input: " + input + " | odt: " + odt );
输入:2016-08-30T18:07:17+0200 | odt:2016-08-30T18:07:17+02:00


奇怪的我假设您正在使用多个线程。您是否考虑过使用新的java8日期api,或者使用
JodaTime
?是的,我使用不同的线程(main和AsyncQueryWorkerThread)。我不认为java8适用于较旧的api级别afaik?问题是,在大多数情况下,它工作时,有时返回随机值或重置日期/时间是有意义的。java8中内置的许多功能,后来在项目中被重新移植到Java6和Java7,并在项目中进一步适应Android。奇怪。。。我假设您正在使用多个线程。您是否考虑过使用新的java8日期api,或者使用
JodaTime
?是的,我使用不同的线程(main和AsyncQueryWorkerThread)。我不认为java8适用于较旧的api级别afaik?问题是,在大多数情况下,它工作时,有时返回随机值或重置日期/时间是有意义的。java8中内置的许多功能,后来在项目中被移植到Java6和Java7,并在项目中进一步适应Android。