我一直在假设既不是线程安全的Date
也不Calendar
是线程安全的,但是,在最近的一次讨论中,一位同事告诉我Calendar
是线程安全的。
所以,我做了一些研究,并没有想出任何东西。有很多人认为它是线程安全的,也有很多人认为它不是线程安全的。而且,最重要的是,文档并没有以某种方式说明任何事情,没有 for Calendar
,甚至也没有 for Date
。
那么,它是什么?
这是Java 7中Calendar和GregorianCalendar源代码的链接
如果您阅读代码,您将看到没有一个实例方法是同步的,并且没有一个实例字段是volatile
. 您还将看到,即使是字段get
方法也可能导致 Calendar 实例发生变异。而且由于没有执行同步,不同的线程可能会在这样的变异操作之后看到日历对象字段的陈旧版本。
作为记录,字段 get 方法中的突变操作发生在 / 调用此方法期间:
1555 protected void complete()
1556 {
1557 if (!isTimeSet)
1558 updateTime();
1559 if (!areFieldsSet || !areAllFieldsSet) {
1560 computeFields(); // fills in unset fields
1561 areAllFieldsSet = areFieldsSet = true;
1562 }
1563 }
简而言之,Calendar
该类不是线程安全的,GregorianCalendar
也不是因为它继承了非线程安全的字段和方法。
但不要只相信我的话。自己分析源代码。
而且,最重要的是,文档没有以任何方式说明任何内容,对于日历,甚至对于日期都没有。
如果 javadocs 没有指定类的线程安全性,那么您应该假设它不是线程安全的。(特别是如果类在设计上是可变的。)
Oracle 的文档没有提到线程安全:http ://docs.oracle.com/javase/7/docs/api/java/util/Calendar.html 。
OpenJDK 源代码(build b147)java.util.Calendar
以非线程安全的方式实现,例如:
public void setTimeInMillis(long millis) {
// skipped
time = millis;
isTimeSet = true;
areFieldsSet = false;
computeFields();
areAllFieldsSet = areFieldsSet = true;
}
我认为可以安全地假设该类不是线程安全的。