powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Java [игнор отключен] [закрыт для гостей] / Пример безопасной, небезопасной и публикации через гонку.
27 сообщений из 27, показаны все 2 страниц
Пример безопасной, небезопасной и публикации через гонку.
    #39397907
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Хочу таки чётко разобраться:

1. final
есть такой класс( модель, версия 1 ):

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
class Foo{
    private final Map map;
     Foo(){
         map = new HashMap();
         map.put(1,"object");
     }

     public void bar(){
       System.out.println(map.get(1));
     }
}



Это пример публикации через гонку( публикация, версия 1 ).
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
public class Main {
    private static Foo foo;

    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                foo = new Foo();
            }
        }).start();


        new Thread(new Runnable() {
            @Override
            public void run() {
                while (foo == null) ; // empty loop

                foo.bar();
            }
        }).start();

    }
}


так как map объявлена final - это валидно и на экран гарантированно будет выведено 1

2.volatile
А что если сделать так( модель версия 2 ):

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
class Foo{
    private volatile Map map;
     Foo(){
         map = new HashMap();
         map.put(1,"object");
     }

     public void bar(){
       System.out.println(map.get(1));
     }
}


Я так понимаю, что публикация, версия 1 ничего нам не гарантирует.
Как в таком случае безопасно опубликовать? ( публикация, версия 2 ):

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
class Main {

    public static void main(String[] args) {
        Foo foo = new Foo();
        new Thread(new Runnable() {
            @Override
            public void run() {
                foo.bar();
            }
        }).start();
    }
}




3. без volatile/final

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
class Foo{
    private Map map;
     Foo(){
         map = new HashMap();
         map.put(1,"object");
     }

     public void bar(){
       System.out.println(map.get(1));
     }
}


я так понимаю публикация, версия 1 и публикация, версия 2 работать не будут. По поводу публикация, версия 2 я совсем не уверен.
Есть ли при такой имплементации способ безопасно опубликовать объект? (может быть через synchronized ?)

Я бы хотел в ответ на этот пост получить:
1. Оценку того, что я написал
2. Понять какие ещё способы безопасной публикации возможны(желательно полный пример кода Main).
3. Если что-то написано неправильно, то прошу разъяснить в деталях, что именно, почему и как поправить.
4. Может ли какой-то из предложенных вариантов вывалить NullPointerException
...
Рейтинг: 0 / 0
Пример безопасной, небезопасной и публикации через гонку.
    #39397930
scf
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Для начала, 1 - это невалидно.
Код сначала публикует ссылку на мапу, а потом её меняет. Нужно наоборот:

Код: java
1.
2.
3.
4.
5.
6.
private final Map map = makeMap()
private Map makeMap() {
         Map map = new HashMap();
         map.put(1,"object");
         return map;
}



Все-таки почитайте оригинальный документ по JMM, ну или статьи на хабре какие-нибудь.
...
Рейтинг: 0 / 0
Пример безопасной, небезопасной и публикации через гонку.
    #39398008
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
scfДля начала, 1 - это невалидно.
Код сначала публикует ссылку на мапу, а потом её меняет. Нужно наоборот:

Код: java
1.
2.
3.
4.
5.
6.
private final Map map = makeMap()
private Map makeMap() {
         Map map = new HashMap();
         map.put(1,"object");
         return map;
}



Все-таки почитайте оригинальный документ по JMM, ну или статьи на хабре какие-нибудь.\


Честно признаюсь, я не достаточно подготовлен для чтения JMM. Если Вы действительно этом можете, я искренне за Вас рад. Статьи на хабре почитаны.

Насколько я понял моментом публикации final поля является завершение конструктора и магический freeze action всё сделает.

То, что говорите Вы, справедливо для volatile.

Раз даже в этом мы не сходимся, хотелось бы ссылку на какую-нить статью, которая это объясняет. Ну или мнение большинства меня тоже убедит, но я так понял, большинство пишущих тут не знают ответа, а на всякий случай перестраховываются.
...
Рейтинг: 0 / 0
Пример безопасной, небезопасной и публикации через гонку.
    #39398075
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
scf,

Также в пользу своей точки зрения могу привести топик со SO
...
Рейтинг: 0 / 0
Пример безопасной, небезопасной и публикации через гонку.
    #39398076
scf
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Пересмотрел JMM.
Оказалось, что я был неправ и мапу даже так публиковать нельзя.
freeze относится только к самим final-полям, и НЕ относится к содержимому объектов

Но у x86 модель памяти достаточно строгая и многие "неправильные" практики на самом деле работают.

Вот интересная статья на тему:
https://shipilev.net/blog/2014/safe-public-construction/
...
Рейтинг: 0 / 0
Пример безопасной, небезопасной и публикации через гонку.
    #39398082
scf
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questioner,

имхо неправильный у них ответ. Мешают в кучу JMM (теорию) и барьеры (конкретную реализацию на конкретных процессорах).
Плюс цитируют одно (объект называется полностью инициализированным и после этого его final поля видны), а выводы делают другие (объект полностью инициализирован, значит, полностью виден)
...
Рейтинг: 0 / 0
Пример безопасной, небезопасной и публикации через гонку.
    #39398127
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
scfПересмотрел JMM.
Оказалось, что я был неправ и мапу даже так публиковать нельзя.
freeze относится только к самим final-полям, и НЕ относится к содержимому объектов

Это само собой. Но h-b отношение появляется при inplace инициализации final поля. А соответственно после разморозки должно быть видно.
...
Рейтинг: 0 / 0
Пример безопасной, небезопасной и публикации через гонку.
    #39398172
scf
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сергей Арсеньев,

эээ где это написано, что инициализация final поля - это точка HB?
...
Рейтинг: 0 / 0
Пример безопасной, небезопасной и публикации через гонку.
    #39398283
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
scf,
jsr-133 9.2.2
Код: plaintext
1.
2.
  hb   hb   mc
w ⇒ f  ⇒ a ⇒ r
               1

между записью и фризом есть барьер. Соответственно, то что было до записи (вызов функции) за ним должно обеспечиваться
...
Рейтинг: 0 / 0
Пример безопасной, небезопасной и публикации через гонку.
    #39398292
scf
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сергей Арсеньев,

барьер-то есть, но в JMM ничего про барьеры не написано, это деталь реализации JVM.
...
Рейтинг: 0 / 0
Пример безопасной, небезопасной и публикации через гонку.
    #39398294
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
scf,

hb не увидел на рисунке?
...
Рейтинг: 0 / 0
Пример безопасной, небезопасной и публикации через гонку.
    #39398303
scf
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сергей Арсеньев,

это в каком конкретно документе? Можете ткнуть вот сюда: http://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.4
?
...
Рейтинг: 0 / 0
Пример безопасной, небезопасной и публикации через гонку.
    #39398306
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
scf,

В документе jsr-133 , а не в ее краткой выжимке.
...
Рейтинг: 0 / 0
Пример безопасной, небезопасной и публикации через гонку.
    #39398330
scf
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сергей Арсеньев,

Учитывая, что официальная страница JCP ведет на JLS , где ничего такого нет, я все больше склоняюсь к мысли, что авторы JMM просто активно притягивают свою модель к реальному железу .
...
Рейтинг: 0 / 0
Пример безопасной, небезопасной и публикации через гонку.
    #39398337
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
scf,

если хорошо пороешься, то и на этот сайт оттуда же попадешь.
Прячут все как партизаны
...
Рейтинг: 0 / 0
Пример безопасной, небезопасной и публикации через гонку.
    #39398345
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Если я правильно понял, jsr-133 - это спецификация модели памяти какой должна быть (начиная с 1.5).
А JLS приведенная тобой - это дока по ее реализации в конкретной версии.
Увы но вторая менее подробная, чем первая. В ней такие вопросы сглажены.
...
Рейтинг: 0 / 0
Пример безопасной, небезопасной и публикации через гонку.
    #39398416
no56892
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
class Foo{
    private volatile Map map;
     Foo(){
         map = new HashMap(); // в map др. потоки увидят ссылку
         map.put(1,"object"); // а этот элемент - не факт

         // а вот так - ОК все, кстати здесь более большой что-ли happens before c final
         Map local = new HashMap();
         local.put(1, "object");
         map = local;
     }

     public void bar(){
       System.out.println(map.get(1));
     }
}


Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
class Main {

    public static void main(String[] args) {
        Foo foo = new Foo();  // 1
        new Thread(new Runnable() {
            @Override
            public void run() {
                foo.bar();
            }
        }).start(); // 2 здесь вообще happens before на Thread.start, все, что до него видно всем.
    }
}
...
Рейтинг: 0 / 0
Пример безопасной, небезопасной и публикации через гонку.
    #39398444
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
no56892
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
class Main {

    public static void main(String[] args) {
        Foo foo = new Foo();  // 1
        new Thread(new Runnable() {
            @Override
            public void run() {
                foo.bar();
            }
        }).start(); // 2 здесь вообще happens before на Thread.start, все, что до него видно всем.
    }
}




согласен. Да, очевидно.
...
Рейтинг: 0 / 0
Пример безопасной, небезопасной и публикации через гонку.
    #39398446
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
no56892
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
class Foo{
    private volatile Map map;
     Foo(){
         map = new HashMap(); // в map др. потоки увидят ссылку
         map.put(1,"object"); // а этот элемент - не факт

         // а вот так - ОК все, кстати здесь более большой что-ли happens before c final
         Map local = new HashMap();
         local.put(1, "object");
         map = local;
     }

     public void bar(){
       System.out.println(map.get(1));
     }
}




А можете пояснить фразу про больший happens-before: Что это значит и у кого он больше?
...
Рейтинг: 0 / 0
Пример безопасной, небезопасной и публикации через гонку.
    #39398459
Alexey Tomin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
scfСергей Арсеньев,

Учитывая, что официальная страница JCP ведет на JLS , где ничего такого нет, я все больше склоняюсь к мысли, что авторы JMM просто активно притягивают свою модель к реальному железу .

Не читайте кукбук! Ещё раз- это простейший пример частичного выполнения JMM. Hostspot jvm работает не так .

Сергей АрсеньевА JLS приведенная тобой - это дока по ее реализации в конкретной версии.

нет
...
Рейтинг: 0 / 0
Пример безопасной, небезопасной и публикации через гонку.
    #39398468
no56892
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questioner,
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
class C {
    public static int var1;
    public static int var2;
}

class B { 
    public B() {
         C.var2 = 10;
    }
}

class A {
    final B bRef = new B();
}

в потоке 1:
С.var1 = 10;
sharedRef = new A(); //dirty write

в потоке 2:
if(sharedRef != null) { //dirty read
    C.var2 == 10 // true
    C.var1 == 10 // нет гарантий, а если вместо final сделать volatile то true гарантированно
    // условно final в конструкторе дает видимость
 //ТОЛЬКО над теми изменениями, сделанными через это 
//final поле (через ссылку) - явно или неявно, а с volatile -
 //вообще над всеми (естественно, которые были до записи в volatile поле).
}
...
Рейтинг: 0 / 0
Пример безопасной, небезопасной и публикации через гонку.
    #39398475
no56892
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Да кстати, еще одно интересное отличие для volatile в вышеописанном случае, что-бы увидеть этот самый hb, ее нужно прочитать, в тоже время манипуляции через final поля в конструкторе - дают видимость и без их чтения.
...
Рейтинг: 0 / 0
Пример безопасной, небезопасной и публикации через гонку.
    #39398476
no56892
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Кароче, в итоге:
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
Если final B bRef = new B();

в потоке 2:
if(sharedRef != null) { //dirty read
    C.var2 == 10 // true
    C.var1 == 10 // не гарантированно
}

Если volatile B bRef = new B();

в потоке 2:
if(sharedRef != null) { //dirty read
    C.var2 == 10 // не гарантированно
    C.var1 == 10 // не гарантированно
}
А так:
в потоке 2:
if(sharedRef != null) { //dirty read
    sharedRef.getBReference() // или любым образом прочитать volatile
    C.var2 == 10 // true
    C.var1 == 10 // true
}
...
Рейтинг: 0 / 0
Пример безопасной, небезопасной и публикации через гонку.
    #39398538
Alexey Tomin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
no56892Да кстати, еще одно интересное отличие для volatile в вышеописанном случае, что-бы увидеть этот самый hb, ее нужно прочитать, в тоже время манипуляции через final поля в конструкторе - дают видимость и без их чтения.

Что такое видимость без чтения?
...
Рейтинг: 0 / 0
Пример безопасной, небезопасной и публикации через гонку.
    #39398574
no56892
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Alexey Tomin,
Что бы увидеть действия произошедшие в кнструкторе через ссылку final поля не обязательно читать само final поле перед этим. См пример выше со Статик переменными.
...
Рейтинг: 0 / 0
Пример безопасной, небезопасной и публикации через гонку.
    #39398817
questioner
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
no56892questioner,
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
class C {
    public static int var1;
    public static int var2;
}

class B { 
    public B() {
         C.var2 = 10;
    }
}

class A {
    final B bRef = new B();
}

в потоке 1:
С.var1 = 10;
sharedRef = new A(); //dirty write

в потоке 2:
if(sharedRef != null) { //dirty read
    C.var2 == 10 // true
    C.var1 == 10 // нет гарантий, а если вместо final сделать volatile то true гарантированно
    // условно final в конструкторе дает видимость
 //ТОЛЬКО над теми изменениями, сделанными через это 
//final поле (через ссылку) - явно или неявно, а с volatile -
 //вообще над всеми (естественно, которые были до записи в volatile поле).
}



а что такое sharedRef?
можно весь код? у вас тут и var1 и var2 без final/volatile
...
Рейтинг: 0 / 0
Пример безопасной, небезопасной и публикации через гонку.
    #39399173
Leonid Kudryavtsev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
questionerХочу таки чётко разобраться....

Было у меня полгода назад такое же желание. Но после прочтения статьи/иследования по поводу производительности new и final в мултипоточной среде... оно прошло ))) Там где-то по середине работы по разбору кода JVM (выделения памяти new) , народ просто написал (по английски и вежливее) "бл?*:! Так у нас тут ошибка и возможны гонки" - после чего я понял, что в subj разбирается чуть больше, чем никто. По крайне мере, авторы JVM точно "таки четко" не разбираются ))). Т.ч. свои желания подавил и просто копи пастом взял готовый алгоритм )))
...
Рейтинг: 0 / 0
27 сообщений из 27, показаны все 2 страниц
Форумы / Java [игнор отключен] [закрыт для гостей] / Пример безопасной, небезопасной и публикации через гонку.
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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