Как сделать статический поток календаря безопасным

Я хотел бы использовать календарь для некоторых статических методов и использовать статическое поле:

private static Calendar calendar = Calendar.getInstance();

Теперь я читаю java.util.Calendar не является потокобезопасным. Как я могу сделать этот поток безопасным (он должен быть статическим)?

Ответ 1

Вы не можете сделать что-то потокобезопасным, если это не так. В случае 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

Это довольно неприятно. У вас может быть только один синхронизированный метод, который создавал клон исходного календаря каждый раз, когда это было необходимо, конечно... возможно, что, вызывая computeFields или computeTime, вы можете сделать последующие операции чтения с потоком Конечно, но лично я был бы не против, чтобы попробовать.

Ответ 2

Календарь является потокобезопасным, если вы его не изменяете. Использование в вашем примере прекрасно.

Стоит отметить, что Календарь не является эффективным классом, и вы должны использовать его только для сложных операций (например, поиск следующего месяца/года). IMHO: Если вы используете его для сложных операций, используйте только локальные переменные.

Если вы хотите, чтобы это был моментальный снимок времени, более быстрый способ - использовать currentTimeMillis, который даже создает объект. Вы можете сделать поле volatile, если вы хотите сделать его потокобезопасным.

private static long now = System.currentTimeMillis();

Использование немного подозрительно. Зачем вам получать текущее время и хранить его в глобальном масштабе. Это напоминает мне старую шутку.

- У вас есть время?
- Да, я его где-то записал.

Ответ 3

Вы не можете. Да, вы можете синхронизировать его, но у него все еще есть изменяемые поля состояния. Вам нужно будет создать свой собственный объект Calendar.

Если возможно, используйте что-то легкое, как длинное измерение времени в миллисекундах, и только конвертируйте в Календарь, когда вам НУЖНО.

Ответ 4

Создайте Calendar как локальную переменную в методе. Если вам нужен один и тот же календарь в разных методах, вы можете использовать статику, где более подходящим является объект (singleton или quasi-singleton).