如何使静态日历线程安全

时间:2011-06-05 18:51:23

标签: java static calendar thread-safety

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

private static Calendar calendar = Calendar.getInstance();

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

4 个答案:

答案 0 :(得分:14)

如果不是,你不能做一些线程安全的东西。在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来实现当然,可以使后续读取操作成为线程安全的,但我个人不愿意尝试它。

答案 1 :(得分:4)

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

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

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

private static long now = System.currentTimeMillis();

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

  

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

答案 2 :(得分:2)

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

如果可能,请使用轻量级的内容,例如长时间测量时间(以毫秒为单位),并在需要时仅转换为日历。

答案 3 :(得分:-1)

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