How to make a static Calendar thread safe

2019-01-24 10:33发布

I'd like to use a Calendar for some static methods and use a static field:

private static Calendar calendar = Calendar.getInstance();

Now I read java.util.Calendar isn't thread safe. How can I make this thread safe (it should be static)?

4条回答
Viruses.
2楼-- · 2019-01-24 10:55

Create a Calendar as a local variable in the method. If you need the same calendar across methods, you may be using statics where a (singleton or quasi-singleton) object would be more appropriate.

查看更多
放荡不羁爱自由
3楼-- · 2019-01-24 10:58

You can't make something thread-safe if it isn't. In the case of Calendar, even reading data from it isn't thread-safe, as it can update internal data structures.

If at all possible, I'd suggest using Joda Time instead:

  • Most of the types are immutable
  • The immutable types are thread-safe
  • It's a generally much better API anyway

If you absolutely have to use a Calendar, you could create a locking object and put all the access through a lock. For example:

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

It's pretty nasty though. You could have just one synchronized method which created a clone of the original calendar each time it was needed, of course... it's possible that by calling computeFields or computeTime you could make subsequent read-operations thread-safe, of course, but personally I'd be loathe to try it.

查看更多
看我几分像从前
4楼-- · 2019-01-24 11:02

Calendar is thread safe provided you don't change it. The usage in your example is fine.

It is worth noting that Calendar is not an efficient class and you should only use it for complex operations (like finding the next month/year) IMHO: If you do use it for complex operations, use local variables only.

If all you want it a snapshot of the time a faster way is to use currentTimeMillis which does even create an object. You can make the field volatile if you want to make it thread safe.

private static long now = System.currentTimeMillis();

The usage is a bit suspect. Why would you get the current time and store it globally like this. It reminds me of the old joke.

- Do you have the time?
- Yes, I have it written down somewhere.

查看更多
beautiful°
5楼-- · 2019-01-24 11:03

You cannot. Yes, you could synchronize on it, but it still has mutable state fields. You'll have to create your own Calendar object.

If possible, use something lightweight, like a long measuring the times in milliseconds, and only convert to a Calendar when you NEED to.

查看更多
登录 后发表回答