Как стать автором
Обновить

Комментарии 30

Не существует Oracle JVM. Вероятно, вы имели ввиду HotSpot.
Понятно, при сравнении двух обёрток оператором == (!=) никакого autoboxing не происходит. Вообще говоря, именно первое равенство смущает. Дело в том, что для целых значений i: -129 < i < 128 объекты-обёртки Integer кэшируются. Поэтому для i из этого диапазона Integer.valueOf(i) не создаёт каждый раз новый объект, а возвращает уже созданный.

А вот если бы не принудительный, где надо и не надо, ООП то этого бессмысленного дроча бы не было. По моему мнению если даже для сравнения чисел мне надо иметь ввиду какие то грабли, то тут явно что то не так…
Никаких граблей, просто в Java значения сравниваются с помощью equals.
НЛО прилетело и опубликовало эту надпись здесь
Никаких граблей

Ну такое себе:


// a == null
a.equals(b);
// NullPointerException
Objects.equals(a, b);
Вообще говоря, синглтоны считаются не самой лучшей практикой.

Как вежливо и дипломатично получилось.
Жёстче надо с ними, синглтоны — вирусное зло в ООП и неисчерпаемый источник граблей!))
НЛО прилетело и опубликовало эту надпись здесь
Сколько лет назад уже предложили одиночку-ENUM? Зачем в 2020-м насиловать стюардессу?
Да, вчера ночью об «одиночке-ENUMе» даже и не вспомнил. Наверно, потому, что стараюсь жить без «одиночек». Ну а стюардесса изредка в каком-нибудь проекте возьмёт, да и всплывёт…

Для некоторых платформ улучшение возможно — по ссылке в статье Шипилев показал небольшую разницу для ARM.


На x86 разницы быть действительно не может — там чтение из volatile «бесплатное» (нет оверхеда, если не считать запрет на reordering)

Дело в том, что для целых значений i: -129 < i < 128 объекты-обёртки Integer кэшируются.

Для начинающих и не только:
Я бы добавил еще что нет верхнего предела. Точнее он есть, но его можно изменить.

github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/lang/Integer.java#L1010
Спасибо, добавил.

hashCode не является адресом объекта, кажется, ещё с версии 1.2. Что изменилось в Java 9 — так это исправили javadoc. Однако даже до этого было сказано, что оно может быть реализовано так, но это не требуется спецификацией. Не стоит выдавать желаемое за действительное.


Однако, при помощи -XX:hashCode=4 можно вернуть желаемое поведение.

Спасибо, про -XX:hashCode=4 я совсем забыл. Сейчас добавлю.

Версии java, начиная с которой поведение изменилось, в статье не указывалось.

Согласен, в данном месте следовало вставить оговорку, что это являлось особенностью конкретной jvm и спецификацией не требовалось. Сейчас вставлю.
Когда-то это было так.Теперь, как минимум с 11-ой версии java, это не так.

Как минимум с 9ой исправлен javadoc — и даже в минимум Sun JRE 1.2 hashCode не возвращал адрес объекта. Т.е референс, что когда-то это было так — сомнительный.

hashCode не может возвращать адрес объекта с тех пор, как GC научился эти самые объекты перемещать (естественно, не меняя их хеш-кода)

Скорее, с этого момента hashCode пришлось записывать.

Это ж одно и то же.

может или не может — это вопрос второй, в теории никто не запрещает это делать, ведь hash-функция нужна для того, чтобы превращать поиск в hash-структурах из O(N) в O(1).
Но коллизии неизбежны

Как раз таки запрещает: значение хеш-функции обязано быть детерминированным, и не имеет права меняться в ходе сборки мусора. Иначе положенные в хеш-таблицу записи потом будет не найти.

Вычисленный hashCode по-умолчанию хранится в заголовке объекта и уже не меняется.
Я имел в виду, что никто не запрещает, чтобы это значение было вычислено как адрес объекта, или просто константа (-XX:hashCode=5 кажется)

Подход не работает по следующим причинам. (read 1, check 1) и (read 3) не синхронизированы. По концепции модели памяти java, изменения, сделанные в другом потоке, могут быть невидимы нашему потоку, пока мы не синхронизируемся.

Здесь вы неправильно описываете проблему. Да, read1 и read3 не синхронизированы, но проблема не в другом потоке. А в том, что несинхронизированные чтения могут быть переупорядочены, т.е. read1 != null, но read3 == null. И заодно, из-за "instance = new Singleton();" мы можем получить ссылку на объект до того, как он был до конца сконструирован, и это действительно проблема синхронизации с другим потоком, но не read1 и read3, а read3 и доступа к членам instance.

Спасибо, согласен. Хотелось написать проще, вот и доупрощался. Сейчас починю.

Кстати, в одном из последних докладов АШ показывал, что volatile можно убрать из объявления поля собственно одиночки, перенеся его в объявление поля supplier (расширение вашего пример). Таким образом, мы сможем избежать волатильного доступа при чтении уже созданного одиночки.

И заодно, из-за «instance = new Singleton();» мы можем получить ссылку на объект до того, как он был до конца сконструирован

А разве ссылка на объект не будет сохранена в поле instance только после завершения работы конструктора (вызова )? Можете показать пример, доказывающий Ваше утверждение? (случай утечек ссылок this из самого конструктора исключаем)

Java Memory Model.
Другой поток может увидеть, что в instance сохранена ссылка на объект, но не увидеть записи в члены объекта, если нет happens-before между его чтениями и записями создавшего объект потока. А если читающий поток не заходил в syncronized, а он мог не заходить, то happens-before нет.


И примеры в статье-источнике, которые показывают, что оно таки ломается.

Спасибо за ссылку на статью Шипилёва, достаточно интересно, хотя некоторые места и вызывают недоумение (в плане работы jvm).
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Изменить настройки темы

Истории