2015-11-06 4 views
1

Я экспериментировал с проблемой видимости потока Java с популярным примером отправки сигнала остановки в поток с помощью общей логической и нелетучей переменной, и целевой поток, похоже, не получил ее) как показано ниже:Видимость и синхронизация потока Java

public class ThreadVisibilityTest { 

    //Shared variable to send a signal to the thread 
    static boolean stopped = false; 

    public static void main(String[] args) throws Exception { 

     Thread targetThread = new Thread(new Runnable() { 
       public void run() { 
       while(!stopped) {} 
       System.out.println("Target thread gets signal and stops..."); 
       } 
       }); 

     targetThread.start(); 

     TimeUnit.SECONDS.sleep(5); 
     stopped=true; 
     System.out.println("Main thread has sent stop signal to the thread..."); 

    } 

} 

Основной поток посылает сигнал остановки на целевой нити через 5 секунд с помощью установки stopped к истинному и целевой поток не может получить его и так не прекращается.

stopped переменный как volatile, очевидно, решает проблему.

Бу-то я понял, что если я stopped переменную non volatile, но вместо того, чтобы получить доступ к нему в synchronized контексте в целевом потоке, целевой поток получает окончательное значение и останавливается. Поэтому проблема видимости потока, похоже, решена так же, как с использованием volatile.

Thread targetThread = new Thread(new Runnable() { 
      public void run() { 
       while(true) { 
        synchronized(this) { 
         if(stopped) break; 
        } 
       } 
       System.out.println("Target thread gets signal and stops..."); 
      } 
     }); 

А также монитор объекта, который будет использоваться для синхронизации, кажется, не имеет никакого эффекта следующим образом:

synchronized(Thread.class) { 
     if(stopped) break; 
} 

Является ли это то, что происходит случайно или я что-то пропустил? Или можно сказать, что доступ к общей переменной с взаимным исключением, по-видимому, заставляет целевой поток обновлять свою кэш-память так же, как доступ к переменной volatile?

Если последнее верно, в каком направлении вы предлагаете преодолеть проблему видимости потоков, используя ключевое слово volatile или доступ с взаимным исключением?

Заранее спасибо

+0

Если вы знаете, что нужно использовать самое последнее значение этой переменной, почему бы вам не использовать volatile? Что вы видите в этом как проблема? –

+0

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

+0

Я не собираюсь выбирать нестабильность.Я просто пытаюсь понять, почему взаимное исключение также решает проблему видимости памяти, как я протестировал, и видел, что доступ к общей переменной с взаимным исключением заставляет вас получить свое окончательное значение так же, как volatile. – Serdar

ответ

0

Я думаю, что взаимное исключение также обеспечивает видимость памяти, как указано в Java Параллелизм В практике (Брайан Гетц) в разделе 3.1.3 Блокировка и видимость.

2

Это что-то, что случается случайно или мне что-то не хватает?

Вы пропустили главу в Справочнике по языку Java (JLS), в которой рассказывается о модели памяти Java. Либо это, либо вы пропустили работу в главе concurrency в учебнике по Java. https://docs.oracle.com/javase/tutorial/essential/concurrency/

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

0

См., Вы читаете его в синхронизированном контексте, но не записываете в синхронизированном контексте. Это может вызвать проблемы.

Смежные вопросы