powered by simpleCommunicator - 2.0.49     © 2025 Programmizd 02
Форумы / Java [игнор отключен] [закрыт для гостей] / Почему DCL без volatile работает для 32-bit примитивов ?
15 сообщений из 15, страница 1 из 1
Почему DCL без volatile работает для 32-bit примитивов ?
    #39864045
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
P.S. я знаю, что не надо использовать DCL. интерес сугубо академический.

Решил изучить таки первоисточник с описанием проблемы DCL: http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
Вот есть такой код:




Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
// Broken multithreaded version
// "Double-Checked Locking" idiom
class Foo { 
  private Helper helper = null;
  public Helper getHelper() {
    if (helper == null) 
      synchronized(this) {
        if (helper == null) 
          helper = new Helper();
      }    
    return helper;
    }
  // other functions and members...
  }



Ну и как мне уже давно известно это не будет работать потому, что поток, который не входит в критическую секцию может увидеть helper уже не null, но конструктор Helper ещё не закончился. Всё вроде ясно кроме одной детали. А что если конструктор пустой? в этом случае проблема тоже будет?

Также там пишут, что
авторAlthough the double-checked locking idiom cannot be used for references to objects, it can work for 32-bit primitive values (e.g., int's or float's). Note that it does not work for long's or double's, since unsynchronized reads/writes of 64-bit primitives are not guaranteed to be atomic.

И мол вот так работать будет:
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
// Correct Double-Checked Locking for 32-bit primitives
class Foo { 
  private int cachedHashCode = 0;
  public int hashCode() {
    int h = cachedHashCode;
    if (h == 0) 
    synchronized(this) {
      if (cachedHashCode != 0) return cachedHashCode;
      h = computeHashCode();
      cachedHashCode = h;
      }
    return h;
    }
  // other functions and members...
  }



Но что-то я ума не приложу почему. Вот допустим первый тред выполнил строку
Код: java
1.
cachedHashCode = h;



Второй тред может увидеть, что эта строка выполнилась, но при этом не увидеть предыдущие две строки. Но в этом случае я вообще хз что он может увидеть. По всей видимости тут оптимизации сработать не должны. Только я не понимаю почему.
...
Рейтинг: 0 / 0
Почему DCL без volatile работает для 32-bit примитивов ?
    #39864070
Leonid Kudryavtsev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerВторой тред может увидеть, что эта строка выполнилась, но при этом не увидеть предыдущие две строки. Но в этом случае я вообще хз что он может увидеть. По всей видимости тут оптимизации сработать не должны. Только я не понимаю почему.

Раз не null - значит результат подсчитан
Поскольку он int, он атомарный (т.е. не может быть не до конца записанный/подсчитанный /в отличие от объекта/)

Т.ч. "не увидить предыдущие две строки" он физически не может. Что значет "не увидеть", когда результат уже есть и он корректный (т.к. атомарный)

IMHO Хороший вопрос Вы задали, эта хренотень с непольностью проинициализированными объектами мне вообще не понятна (((, в свое время дофига времени потерял на отладке проекта, где это вылезало

AFAIK Если класс объявлен как имутабельный, то вроде конструктор гарантирует атомарность инициализацию объекта и такой хренотени быть не должно, надеюсь точную ссылку на доку кто нибудь сможет дать, у меня под рукой нет
...
Рейтинг: 0 / 0
Почему DCL без volatile работает для 32-bit примитивов ?
    #39864077
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Leonid Kudryavtsev,

спасибо за ответ


Leonid KudryavtsevAFAIK Если класс объявлен как имутабельный, то вроде конструктор гарантирует атомарность инициализацию объекта и такой хренотени быть не должно, надеюсь точную ссылку на доку кто нибудь сможет дать, у меня под рукой нет

Примерно по поводу этого из той же статьи:

авторIn fact, assuming that the computeHashCode function always returned the same result and had no side effects (i.e., idempotent), you could even get rid of all of the synchronization.

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
// Lazy initialization 32-bit primitives
// Thread-safe if computeHashCode is idempotent
class Foo { 
  private int cachedHashCode = 0;
  public int hashCode() {
    int h = cachedHashCode;
    if (h == 0) {
      h = computeHashCode();
      cachedHashCode = h;
      }
    return h;
    }
  // other functions and members...
  }
...
Рейтинг: 0 / 0
Почему DCL без volatile работает для 32-bit примитивов ?
    #39864083
забыл ник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questioner
Примерно по поводу этого из той же статьи:

авторIn fact, assuming that the computeHashCode function always returned the same result and had no side effects (i.e., idempotent), you could even get rid of all of the synchronization.

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
// Lazy initialization 32-bit primitives
// Thread-safe if computeHashCode is idempotent
class Foo { 
  private int cachedHashCode = 0;
  public int hashCode() {
    int h = cachedHashCode;
    if (h == 0) {
      h = computeHashCode();
      cachedHashCode = h;
      }
    return h;
    }
  // other functions and members...
  }



Если операция идемпотентна и атомарна как в этом случае - то зачем вообще может понадобиться синхронизация? Что-то или кто-то недоговаривает.
Для начала надо определиться что этот код вообще должен делать? Считать хэшкод один раз? Считать несколько но главное чтобы корректно? Или еще что? А что если хэшкод вернет 0, автор не подумал? Короче я не понимаю идею, что вообще хочется понять то?
...
Рейтинг: 0 / 0
Почему DCL без volatile работает для 32-bit примитивов ?
    #39864092
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
забыл никquestionerПримерно по поводу этого из той же статьи:

пропущено...


Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
// Lazy initialization 32-bit primitives
// Thread-safe if computeHashCode is idempotent
class Foo { 
  private int cachedHashCode = 0;
  public int hashCode() {
    int h = cachedHashCode;
    if (h == 0) {
      h = computeHashCode();
      cachedHashCode = h;
      }
    return h;
    }
  // other functions and members...
  }



Если операция идемпотентна и атомарна как в этом случае - то зачем вообще может понадобиться синхронизация? Что-то или кто-то недоговаривает.
Для начала надо определиться что этот код вообще должен делать? Считать хэшкод один раз? Считать несколько но главное чтобы корректно? Или еще что? А что если хэшкод вернет 0, автор не подумал? Короче я не понимаю идею, что вообще хочется понять то?

Закешировать наверное хотят, но я лично не могу понять действительно ли это выполнится только один раз или имеется ввиду, что выполнится и выполнится, всё равно одно и то же вернёт. На ноль решили забить - Шипилёв чо то такое кстати рассказывал кстати применительно к Strring- реально не большая проблема.

Статья - классика. авторSigned by: David Bacon (IBM Research) Joshua Bloch (Javasoft), Jeff Bogda, Cliff Click (Hotspot JVM project), Paul Haahr, Doug Lea, Tom May, Jan-Willem Maessen, Jeremy Manson, John D. Mitchell (jGuru) Kelvin Nilsen, Bill Pugh, Emin Gun Sirer Не самые последние люди в java сообществе. Не находите?
...
Рейтинг: 0 / 0
Почему DCL без volatile работает для 32-bit примитивов ?
    #39864096
забыл ник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerзабыл никпропущено...


Если операция идемпотентна и атомарна как в этом случае - то зачем вообще может понадобиться синхронизация? Что-то или кто-то недоговаривает.
Для начала надо определиться что этот код вообще должен делать? Считать хэшкод один раз? Считать несколько но главное чтобы корректно? Или еще что? А что если хэшкод вернет 0, автор не подумал? Короче я не понимаю идею, что вообще хочется понять то?

Закешировать наверное хотят, но я лично не могу понять действительно ли это выполнится только один раз или имеется ввиду, что выполнится и выполнится, всё равно одно и то же вернёт. На ноль решили забить - Шипилёв чо то такое кстати рассказывал кстати применительно к Strring- реально не большая проблема.

Статья - классика. авторSigned by: David Bacon (IBM Research) Joshua Bloch (Javasoft), Jeff Bogda, Cliff Click (Hotspot JVM project), Paul Haahr, Doug Lea, Tom May, Jan-Willem Maessen, Jeremy Manson, John D. Mitchell (jGuru) Kelvin Nilsen, Bill Pugh, Emin Gun Sirer Не самые последние люди в java сообществе. Не находите?

Статья была написана для java 1.4, я понимаю что ты некромант, но все же. Если computeHashCode вернет 0 - то у этого куда ни при каких раскладах нет шансов выполниться всего лишь раз
...
Рейтинг: 0 / 0
Почему DCL без volatile работает для 32-bit примитивов ?
    #39864103
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
забыл никquestionerпропущено...


Закешировать наверное хотят, но я лично не могу понять действительно ли это выполнится только один раз или имеется ввиду, что выполнится и выполнится, всё равно одно и то же вернёт. На ноль решили забить - Шипилёв чо то такое кстати рассказывал кстати применительно к Strring- реально не большая проблема.

Статья - классика. пропущено...
Не самые последние люди в java сообществе. Не находите?

Статья была написана для java 1.4, я понимаю что ты некромант, но все же. Если computeHashCode вернет 0 - то у этого куда ни при каких раскладах нет шансов выполниться всего лишь раз

Я ж писал, что интерес академический.

Конкретно в этом примере разница есть 11 это джава или 4-ая ?


забыл никЕсли computeHashCode вернет 0 - то у этого куда ни при каких раскладах нет шансов выполниться всего лишь раз

Да я тебя понял. Вероятность такого хешкода ничтожно мала и можно просто принять тот факт, что для такого хешкода мы будем пересчитывать.
вот кстати String#hashCode из java 11
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
    public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            hash = h = isLatin1() ? StringLatin1.hashCode(value)
                                  : StringUTF16.hashCode(value);
        }
        return h;
    }
...
Рейтинг: 0 / 0
Почему DCL без volatile работает для 32-bit примитивов ?
    #39864112
Андрей Панфилов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerЯ ж писал, что интерес академический.

Конкретно в этом примере разница есть 11 это джава или 4-ая ?там внизу же написано все: кто final не использует в синглетонах - тот лох, а по факту в java 5 для volatile запретили reordering и статья об этом.
questionerДа я тебя понял. Вероятность такого хешкода ничтожно мала и можно просто принять тот факт, что для такого хешкода мы будем пересчитывать.У меня в приложении наверное процентов 10 строк пустые, ничтожность аж зашкаливает.
...
Рейтинг: 0 / 0
Почему DCL без volatile работает для 32-bit примитивов ?
    #39864114
забыл ник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questioner
Конкретно в этом примере разница есть 11 это джава или 4-ая ?



Есть, начиная с 5 java - разработчики дали нам solid JMM, которой нао следовать и это гарантирует что твой код будет работать. В 4-ке такой возможности не было
...
Рейтинг: 0 / 0
Почему DCL без volatile работает для 32-bit примитивов ?
    #39864118
Leonid Kudryavtsev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
забыл никЕсли операция идемпотентна и атомарна как в этом случае - то зачем вообще может понадобиться синхронизация?

Слова "идемпотентна" я не знаю )))
А синхронизация в любом случае требуется. Или volatile или synchronize в любом случае должно быть.

IMHO & AFAIK

note: в какой-то момент из примеров кода в данной ветке и volatile и synchronize исчезло. IMHO без них не корректно в любом случае.

забыл никКороче я не понимаю идею, что вообще хочется понять то?

Как я понимаю, главные поинт в начальном топике:

Что объекты НЕ атомарны (в "новых" Java вроде для имутабельных объектов сделали исключение) - и такие финты ушами с объектами НЕ прокатывают.

На эту хренотень с объектами на реальном проекте я и сам нарывался, но честно говоря, в голове плохо укладывается. как после физического завершения конструктора объект все еще не проинициализирован. Тут у меня шарики за ролики заезжают и на понятном, "бытовом" языке IMHO это не объяснимо. Надо переставать мыслить терминами "завершилось"/"увидело" и мыслить только абстрактно в терминах "happens before", что лично для меня достаточно тяжело.

IMHO & AFAIK
...
Рейтинг: 0 / 0
Почему DCL без volatile работает для 32-bit примитивов ?
    #39864121
Leonid Kudryavtsev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
забыл никsolid JMM
кидай ссылки на доку, т.к. google например по "solid JMM" находит чисто мусор и зубную пасту (((
...
Рейтинг: 0 / 0
Почему DCL без volatile работает для 32-bit примитивов ?
    #39864128
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Андрей ПанфиловКонкретно в этом примере разница есть 11 это джава или 4-ая ?там внизу же написано все: кто final не использует в синглетонах [/quot]

Да я тебе больше скажу - кто синглтоны пишет тоже лох.

Андрей ПанфиловУ меня в приложении наверное процентов 10 строк пустые, ничтожность аж зашкаливает.

Это тебе к Шипилёву.
...
Рейтинг: 0 / 0
Почему DCL без volatile работает для 32-bit примитивов ?
    #39864134
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
[quot Андрей Панфилов]questionerтам внизу же написано все: кто final не использует в синглетонах - тот лох

http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html If Helper is an immutable object, such that all of the fields of Helper are final, then double-checked locking will work without having to use volatile fields. The idea is that a reference to an immutable object (such as a String or an Integer) should behave in much the same way as an int or float; reading and writing references to immutable objects are atomic.
...
Рейтинг: 0 / 0
Почему DCL без volatile работает для 32-bit примитивов ?
    #39864423
Alexey Tomin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerВторой тред может увидеть, что эта строка выполнилась, но при этом не увидеть предыдущие две строки. Но в этом случае я вообще хз что он может увидеть. По всей видимости тут оптимизации сработать не должны. Только я не понимаю почему.

Треды не видя строки кода, они видят только данные.
Все проблемы синхронизации проще всего описать в терминах двух процессоров с кэшами.
Первый записал значение в КЭШ, второй прочитал свой кэш- и что там у него- фиг знает.

Объясняя неточно, но понятно:
Вход в synchronized секцию и чтение volatile гарантируют, что все наши кэши обновлены.
Выход из synchronized и запись volatile - гарантируют, что мы все кэши сбросили.

Но при этом в варианте с объектом до проверки if (helper == null) нет никакой синхронизации и в "наш" кэш может приехать только ссылка, но не доехать объект (или приехать только его часть). Для этого нужен volatile - он гарантирует, что до нас доедет только всё целиком.

А когда нам нужно только один примитив- то всё просто- он либо есть, либо его нет.
...
Рейтинг: 0 / 0
Почему DCL без volatile работает для 32-bit примитивов ?
    #39864767
Lelouch
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questioner что не надо использовать DCL

А можно уточнить, почему его не надо использовать?
AFAIK в 1.4 он не работал, но после 1.5 в чем проблема?
...
Рейтинг: 0 / 0
15 сообщений из 15, страница 1 из 1
Форумы / Java [игнор отключен] [закрыт для гостей] / Почему DCL без volatile работает для 32-bit примитивов ?
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]