Частично созданный объект / Много поточная обработка

Я использую joda из-за, он - хорошая репутация относительно много поточной обработки. Это идет большие расстояния для создания многопоточной даты, обрабатывающей эффективный, например, путем создания всех объектов Даты/Времени/Даты и времени неизменными.

Но вот ситуация, где я не уверен, делает ли Joda действительно правильную вещь. Это, вероятно, делает, но мне очень интересно видеть объяснение.

Когда toString () DateTime называют, Joda делает следующее:

/* org.joda.time.base.AbstractInstant */
public String toString() {
    return ISODateTimeFormat.dateTime().print(this);
}

Все средства форматирования ориентированы на многопотоковое исполнение (они неизменный также), но что о фабрике средства форматирования:

private static DateTimeFormatter dt;

/*  org.joda.time.format.ISODateTimeFormat */
public static DateTimeFormatter dateTime() {
    if (dt == null) {
        dt = new DateTimeFormatterBuilder()
            .append(date())
            .append(tTime())
            .toFormatter();
    }
    return dt;
}

Это - общий шаблон в единственных потоковых приложениях, но он, как известно, подвержен ошибкам в многопоточной среде.

Я вижу следующие опасности:

  • Состояние состязания во время пустой проверки-> худший случай: создаются два объекта.

Без проблем, поскольку это - только объект помощника (в отличие от нормальной ситуации с шаблоном "одиночка"), каждый сохраняется в dt, другой потерян и будет собран "мусор" рано или поздно.

  • статическая переменная могла бы указать на частично созданный объект, прежде чем objec был законченной инициализацией

(прежде чем, называя меня сумасшедшим, читайте об аналогичной ситуации в этой статье Wikipedia.)

Таким образом, как Joda гарантирует, что никакое частично созданное средство форматирования не публикуется в этой статической переменной?

Спасибо за Ваши объяснения!

Reto

5
задан reto 25 March 2010 в 10:16
поделиться

3 ответа

Вы сказали, что средства форматирования доступны только для чтения. Если они используют только поля final (я не читал исходный код программы форматирования), то в 3-м издании спецификации языка Java они защищены от создания частичного объекта «Семантикой окончательного поля». Я не проверял 2-ю редакцию JSL и не уверен, правильна ли такая инициализация в этой редакции.

Посмотрите главы 17.5 и 17.5.1 в JLS. Я построю «цепочку событий» для требуемого отношения «происходит до».

Во-первых, где-то в конструкторе есть запись в последнее поле в форматтере. Это запись w. Когда конструктор завершает свою работу, происходит «замораживание». Назовем это f. Где-то позже в порядке выполнения программы (после возврата из конструктора, возможно, некоторых других методов и возврата из toFormatter) есть запись в поле dt. Дадим этому письму имя a. Эта запись (a) находится после действия замораживания (f) в «программном порядке» (порядок в однопоточном выполнении), и, следовательно, f происходит - перед a (hb (f, a)) только по определению JLS. Уф, инициализация завершена ... :)

Иногда позже, в другом потоке, происходит вызов dateTime () .format. На этот раз нам нужно два чтения. Первый из двух считывается последней переменной в объекте форматирования. Назовем его r2 (для согласования с JLS). Второй из двух - это чтение «this» для Formatter. Это происходит во время вызова метода dateTime () при чтении поля dt. Назовем это чтение r1. Что у нас есть сейчас? Прочитал r1 увидел запись в dt.Я считаю, что эта запись была действием a из предыдущего абзаца (только один поток написал это поле для простоты). Поскольку r1 видит запись a, то существует mc (a, r1) (отношение «цепочка памяти», определение первого предложения). Текущий поток не инициализировал средство форматирования, считывает его поле в действии r2 и видит "адрес" средства форматирования, прочитанный в действии r1. Таким образом, по определению существует разыменование (r1, r2) (другой заказ действия из JLS).

У нас есть запись до остановки, hb (w, f). У нас есть замораживание перед назначением dt, hb (f, a). У нас есть чтение из dt, mc (a, r1). И у нас есть цепочка разыменования между r1 и r2, разыменования (r1, r2). Все это приводит к соотношению «случилось раньше» hb (w, r2) только по определению JLS. Также, по определению, hb (d, w), где d - это запись значения по умолчанию для последнего поля в объекте. Таким образом, чтение r2 не может видеть запись w и должно видеть запись r2 (единственная запись в поле из программного кода).

То же самое и для более косвенного доступа к полю (последнее поле объекта хранится в последнем поле и т. Д.).

Но это еще не все! Нет доступа к частично построенному объекту. Но есть более интересный баг. При отсутствии явной синхронизации dateTime () может возвращать null. Не думаю, что такое поведение можно наблюдать на практике, но 3-я редакция JLS не предотвращает такое поведение. Первое чтение поля dt в методе может увидеть значение, инициализированное другим потоком, но второе чтение dt может увидеть «запись значения по умолчанию». Не бывает - пока не существует отношений, которые могли бы предотвратить это.Такое возможное поведение характерно для 3-го издания, второе издание имеет «запись в основную память» / «чтение из основной памяти», что не позволяет потоку видеть значения переменной, возвращающиеся во времени.

4
ответ дан 15 December 2019 в 06:22
поделиться

ИМО в худшем случае создается не два объекта, а несколько (столько, сколько есть потоки, вызывающие dateTime () , если быть точным). Поскольку dateTime () не синхронизируется, а dt не является ни окончательным, ни изменчивым, изменение его значения в одном потоке не гарантируется, что оно будет видимым для других потоков. Таким образом, даже после того, как один поток инициализировал dt , любое количество других потоков может по-прежнему видеть ссылку как нулевую, таким образом успешно создавая новые объекты.

Помимо этого, как объяснили другие, частично созданный объект не может быть опубликован с помощью dateTime () . Также не может быть частично измененная (= висящая) ссылка, поскольку обновления значений ссылки гарантированно будут атомарными.

-1
ответ дан 15 December 2019 в 06:22
поделиться

Это немного не ответ, но самое простое объяснение для

Итак, как Joda гарантирует, что не частично созданный модуль форматирования будет опубликован в этом static variable?

может быть просто потому, что они ничего не гарантируют, и разработчики либо не понимали, что это может быть ошибкой, либо чувствовали, что не стоит выполнять синхронизацию заново.

0
ответ дан 15 December 2019 в 06:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: