2016-08-17 2 views
1

При завершении выполнения синхронизированного блока весь кэш процессора сбрасывается или только тот объект, на котором действует синхронизированный оператор, будет сброшен? В приведенном ниже примере, когда поток завершил выполнение метода2, данные obj2 также покраснели в основную память?Кэш-флеш на синхронизированном входе, выходе и волатильном режиме чтения и записи

class cls1 { 
    int x=10; 
} 

class cls2{ 
    int y=10; 
} 

class cls3{ 
    cls1 obj1; 
    cls2 obj2; 
    public void method2(){ 
     obj2.y=10; 
     synchronized(obj1){ 
      obj1.x=30; 
     } 
    } 

    public static void main(String[] args) { 
     final cls3 obj3 = new cls3(); 

     Thread thread1 = new Thread(){ 
      public void run(){ 
       obj3.method2(); 
      } 
     }; 
     Thread thread2 = new Thread(){ 
      public void run(){ 
       System.out.println(obj3.obj1.x); 
      } 
     }; 
    } 
} 

ответ

3

A происходит до того, как отношение установлено только тогда, когда другой поток также синхронизируется с блокировкой, с помощью которой первая нить обновляла содержимое.

Happens before

В этом примере резьба B после приобретения замокло на тот же объект М, то он будет в состоянии увидеть все изменения, которые были сделаны до и во время синхронизированного блока. Но помните, что блокировка должна быть получена для происходит до.

В вашем примере, потому что System.out.println(obj3.obj1.x); не печатается внутри синхронизированного блока, это не гарантируется раньше.

Ссылки:

EDIT: Отличный ответ Петр What is the scope of memory flushed or published to various threads when using volatile and synchronized?

0

JLS не говорит о кэшей и их согласованности, он использует 'происходит, прежде, чем' отношение для упорядочения операций с несколькими потоками, таких как чтение и запись в общую память. В вашем примере разрешено переупорядочить obj2.y=10, поэтому он идет после блока sync. Плюс, поскольку не существует «произойдет-до», установленного путем ввода/выхода метода, у JMM нет гарантии, что изменение станет видимым после завершения метода.

См. "Java memory model" спецификации Java для подробного объяснения основополагающих принципов.

Кстати, похоже, вы забыли позвонить по start() методу в потоковых экземплярах, которые вы создали в main.

+0

Назначение 'obj2.y = 10' не может быть переупорядочено после блока' synchronized' из-за барьера памяти записи в конце блока. См. Здесь: http://gee.cs.oswego.edu/dl/jmm/cookbook.html – Gray

+0

Кроме того, существует гарантия, что при переходе барьера записи любые грязные блоки (включая 'obj2.y') будут записанных в основную память. См. Тот же документ. Вы правы, что нет гарантии заказа, но есть гарантия на память. – Gray

0

При завершении выполнения синхронизированного блока весь кэш процессора сбрасывается или только тот объект, на котором действует синхронизированный оператор, будет сброшен?

Быстрый ответ: все грязные блоки из кэша процессора очищены.

Когда поток входит в блок synchronized, он пересекает считываемый барьер памяти, который заставляет локальные копии памяти, которые были обновлены в основной памяти, вымываться из кеша локальной процессорной памяти.

Когда поток выходит из блока a synchronized, он пересекает барьер памяти записи, а все локальные процессорные грязные блоки записываются в основную память. Это не просто объект блокировки, а все грязные блоки памяти.

В приведенном ниже примере, когда поток завершенным выполнением метода2, данные obj2 также удаляются в основную память?

Да. Когда поток выходит, есть также барьер памяти записи, который пересекается.

System.out.println(obj3.obj1.x);

Это, вероятно, не будет печатать 30. Важно понимать, что:

  • Там нет никакой гарантии в вашем коде, который thread2 будет запущен после того, как thread1 завершается. Даже если вы запустите thread2 после thread1, условия гонки могут иметь thread2 доступ obj1 произошло доthread1 обновляет его или сбрасывает кеш в центральную память.
  • Кроме того, даже если вы гарантировать, что thread2 код мчит после thread1 отделки, вам нужно будет убедиться, что thread2 пересекает сам барьер памяти для чтения для чтения obj3 из основной памяти и убедитесь, что thread2 видит обновления памяти от thread1 , Это означало бы, что obj3 будет volatile или с thread2 также введите блок synchronized.

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