java.util.Calendar线程是否安全?

2022-09-01 17:16:45

我一直在假设两者都不是线程安全的,但是,在最近的一次讨论中,一位同事告诉我线程安全。DateCalendarCalendar

所以,我做了一些研究,什么也没想出来。有很多人认为它是线程安全的,很多人认为它不是线程安全的。而且,最重要的是,文档没有以这种或那种方式说明任何内容,不是针对 ,甚至不是针对 。CalendarDate

那么,它是什么呢?


答案 1

以下是Java 7中CalendarGregorianCalendar源代码的链接

如果阅读代码,您将看到没有同步任何实例方法,也没有实例字段是 。您还将看到,即使字段方法也可能导致 Calendar 实例发生突变。由于没有执行同步,因此在进行此类更改操作后,不同的线程可能会看到 Calendar 对象字段的过时版本。volatileget

为了记录,现场 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       }

简而言之,该类不是线程安全的,也不是,因为它继承了非线程安全的字段和方法。CalendarGregorianCalendar

但不要只听我说。对源代码进行自己的分析。


而且,最重要的是,文档没有以某种方式说明任何内容,不适用于日历,甚至不适用于日期。

如果 javadocs 没有指定类的线程安全,那么你应该假定它不是线程安全的。(特别是如果类在设计上是可变


答案 2

来自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;
}

我认为可以安全地假设该类不是线程安全的。


推荐