我使用joda,因为它在多线程方面的声誉很好。通过使所有Date/Time/DateTime对象不可变来实现多线程日期处理的效率很高。部分构造的对象/多线程
但是,我不确定乔达是否真的在做正确的事情。它可能会,但我很感兴趣看到一个解释。
当一个DateTime的一个toString()被调用乔达执行以下操作:
/* org.joda.time.base.AbstractInstant */
public String toString() {
return ISODateTimeFormat.dateTime().print(this);
}
所有格式化是线程安全的(他们永恒不变的为好),但什么是关于格式工厂:
private static DateTimeFormatter dt;
/* org.joda.time.format.ISODateTimeFormat */
public static DateTimeFormatter dateTime() {
if (dt == null) {
dt = new DateTimeFormatterBuilder()
.append(date())
.append(tTime())
.toFormatter();
}
return dt;
}
这是单线程应用程序中的一种常见模式,但已知它在多线程环境中容易出错。
我看到以下的危险:空检查期间
- 竞争条件 - >最坏的情况:获得创建两个对象。
没有问题,因为这只是一个辅助对象(与正常的单例模式不同),一个会保存在dt中,另一个会丢失,并且迟早会被垃圾回收。
- 的objec已完成之前初始化
静态变量可能指向一个部分构造的对象(叫我疯狂之前,阅读有关本Wikipedia article类似的情况。)
所以Joda如何确保部分创建的格式化程序不会在此静态变量中发布?
感谢您的解释!
雷托
+1。这是java并发模型中为什么不可变对象更“简单”的另一个原因。但是,我不确定最后一段,请参阅JLS 17.4.4:“向每个变量写入默认值(零,false或null) - 与每个线程中的第一个操作同步”。在读取dt之前发生“写入默认值”是必要的。 – irreputable 2010-03-24 20:45:43
是的,在读取dt之前写入默认值。这可以防止线程读取“垃圾”值。但是在另一个线程中写入字段(初始化dt字段)不与dt读取具有hb关系。因此,我们可以随时看到这两个写入中的任何一个(默认或来自初始化dt的线程)。我们必须读取默认初始值的唯一时间是临时性需求检查。但是那时我们只提交一个默认值的读取,并且在下一次迭代中说,该线程将一个对象写入dt(仅用于该方法中的第一次读取)。 – maxkar 2010-03-25 06:14:33