如何使静态日历线程安全

我想对一些静态方法使用Calendar并使用静态字段:

private static Calendar calendar = Calendar.getInstance(); 

现在我读java.util.Calendar不是线程安全的。 如何使这个线程安全(它应该是静态的 )?

如果不是,你不能做一些线程安全的东西。 对于Calendar ,即使从中读取数据也不是线程安全的,因为它可以更新内部数据结构。

如果可能的话,我建议改用Joda Time :

  • 大多数类型是不可变的
  • 不可变类型是线程安全的
  • 无论如何,它通常是更好的API

如果您必须使用Calendar ,则可以创建锁定对象并通过锁定放置所有访问权限。 例如:

 private static final Calendar calendar = Calendar.getInstance(); private static final Object calendarLock = new Object(); public static int getYear() { synchronized(calendarLock) { return calendar.get(Calendar.YEAR); } } // Ditto for other methods 

虽然这很糟糕。 您可以只使用一个同步方法,每次需要时创建原始日历的克隆,当然……通过调用computeFieldscomputeTime您可以使后续读取操作成为线程安全的,当然,但是我不愿意去试试。

如果您不更改日历,则日历是线程安全的。 您的示例中的用法很好。

值得注意的是,Calendar不是一个高效的类,你应该只将它用于复杂的操作(比如查找下个月/年)恕我直言:如果你将它用于复杂的操作,只能使用局部变量。

如果你只想要它的时间快照,更快的方法是使用currentTimeMillis甚至创建一个对象。 如果要使线程安全,可以使字段变为volatile。

 private static long now = System.currentTimeMillis(); 

用法有点怀疑。 为什么你会得到当前时间并将其存储在全球范围内。 它让我想起了这个老笑话。

– 你有时间吗?
– 是的,我把它写在某个地方。

你不能。 是的,你可以同步它,但它仍然有可变的状态字段。 您必须创建自己的Calendar对象。

如果可能的话,使用轻量级的东西,例如长时间测量时间(以毫秒为单位),并且只在需要时转换为日历。

在方法中将Calendar创建为局部变量。 如果您需要跨方法的相同日历,您可能正在使用静态,其中(单例或准单例)对象更合适。