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

Posted

技术标签:

【中文标题】java.util.Calendar 线程是不是安全?【英文标题】:Is java.util.Calendar thread safe or not?java.util.Calendar 线程是否安全? 【发布时间】:2012-08-21 07:29:20 【问题描述】:

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

所以,我做了一些研究,但一无所获。有很多人认为它是线程安全的,也有很多人认为它不是线程安全的。而且,最重要的是,文档并没有以任何方式说明任何事情,Calendar 没有,甚至Date 也没有。

那么,它是什么?

【问题讨论】:

***.com/questions/6245053/… 看到了 @AlexColeman 请注意,第一个答案是“否”,第二个答案是“是”,所有讨论都没有任何支持。 +1 表示Joda Time。如果您关心线程安全问题,那么使用这将是一个不错的选择。 @DanielC.Sobral 不过,第一个被点赞了 8 次,得到了正确答案,似乎得到了很好的支持 @mojoken 很明显,线程安全涉及使用同一实例的多个线程。 【参考方案1】:

这里是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 没有指定类的线程安全性,那么您应该假设它不是线程安全的。 (特别是如果类是可变的设计。)

【讨论】:

【参考方案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;

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

【讨论】:

以上是关于java.util.Calendar 线程是不是安全?的主要内容,如果未能解决你的问题,请参考以下文章

java.util.Calendar.get* 和 java.util.Calendar.set* 被阻塞

如何使静态日历线程安全

java.util.Date 和 java.util.Calendar 是不是已弃用?

为啥我不应该使用 date4j 而不是 joda java.util.Calendar 或 jsr 310?

java.time.LocalDate的优点

java.util.Calendar简介