После создания объекта устанавливается ли забор памяти с другими потоками?

Может ли кто-нибудь подтвердить мое понимание ограждения памяти, установленного после выполнения конструктора. Например, предположим, что у меня есть класс Stock.

public final class Stock{

       private final String ticker;
       private double qty;
       private double price;

       public Stock ( String ticker, double qty, double price ){
              this.ticker  = ticker;
              this.qty     = qty;
              this.price   = price;

              //I am assuming a memory fence gets inserted here.
       }


       public final void updateQty( double qty ){
           this.qty = qty;
       }


       public final void updatePrice( double price ){
           this.price = price;
       }

}

Кроме того, предположим, что конструктор выполняется Thread1, а затем updateQty() и updatePrice() несколько раз вызываются Thread2 (всегда Thread2).

Я утверждаю, что после того, как Thread1 создает объект, «видимость» объекта устанавливается со всеми другими потоками в jvm. И поскольку две изменяемые переменные изменяются только Thread2, мне не нужна никакая блокировка. Я прав?


person CaptainHastings    schedule 10.10.2012    source источник
comment
Нет - гарантированно будет виден только тикер (потому что он окончательный).   -  person assylias    schedule 11.10.2012
comment
Я думаю, что volatile по количеству и цене поможет здесь - насколько я знаю, конструкция является потокобезопасной (без утечек ссылок), а volatile устанавливает гарантии видимости?   -  person Pyranja    schedule 11.10.2012
comment
Спасибо, ребята, теперь я понимаю, что объект должен быть неизменным (в отсутствие volatile), чтобы иметь какие-либо гарантии видимости.   -  person CaptainHastings    schedule 11.10.2012


Ответы (2)


Я утверждаю, что после того, как Thread1 создает объект, «видимость» объекта устанавливается со всеми другими потоками в jvm.

Это неправильно. Не существует подразумеваемого барьера/ограждения памяти конструктора, поэтому переупорядочение инструкций вокруг конструктора является такой проблемой. Если вы собираетесь использовать объект Stock в другом потоке, отличном от того, в котором он был создан, вам придется выполнить synchronize объект перед вызовом каких-либо методов обновления.

И поскольку две изменяемые переменные изменяются только Thread2, мне не нужна никакая блокировка.

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

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

Это безопасная публикация объекта?

person Gray    schedule 10.10.2012
comment
Спасибо за объяснение и ссылку. Я не знаю, почему я думал, что будет барьер памяти для неконечных/энергонезависимых переменных. - person CaptainHastings; 11.10.2012
comment
Нп @CaptainHastings. Это распространенная ошибка. - person Gray; 11.10.2012

К сожалению нет. Конструктор (в основном) похож на обычный метод в модели памяти Java.

Но это плохо, это создало бесконечную путаницу для программистов.

person irreputable    schedule 10.10.2012
comment
Действительно запутанно. Спасибо за ответ. - person CaptainHastings; 11.10.2012