2015-06-12 3 views
0

Предположим, что у меня есть volatile reference c для MyClass, а MyClass имеет целое поле x. Если один поток изменяет значение x, будет ли новое значение гарантировано видимым для всех других потоков, или же x тоже должен быть изменчивым?Будут ли мутации изменчивой переменной видны для всех потоков?

Другими словами, приведен нижеприведенный пример для печати 2?

public class MyClass { 

private static volatile MyClass c; 

private int x = 1; 

public static void main(String[] args) { 
    c = new MyClass(); 
    Thread thread = new Thread(new Runnable() { 

     @Override 
     public void run() { 
      c.x = 2; 

     } 
    }); 
    thread.start(); 
    try { 
     thread.join(); 
     System.out.println(c.x); 
    } catch (InterruptedException ex) { 
     // 
    } 


} 

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

+0

Вы можете указать код этой проблемы для лучшего понимания – Ansu

+0

Пример кода добавлен. – user155631

ответ

1

Для вашего первого вопроса, да. Volatile гарантирует, что записи в поле volatile видны операциями чтения других потоков. Однако он не каскадирует, поэтому волатильность не вписывается во все варианты использования (т. Е. Только потому, что эта ссылка является волатильной, не означает, что все поля упомянутого объекта волшебным образом становятся летучими).

В большинстве случаев вам необходимо получить доступ, чтобы убедиться, что все записи видны после последующих чтений.

2

Varialbe x также должен быть изменчивым для вашего примера.

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

Чтобы увидеть изменения в коллекции (при условии, что это не параллельная коллекция, скажем, это простой ArrayList), вы должны предоставить монитор самостоятельно.

Object monitor = new Object(); 

synchronized(monitor) { 
    // change collection 
} 

synchronized(monitor) { 
    // read collection 
} 

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

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

+0

Спасибо. Если используются параллельные коллекции (используя команду Collections.synchronizedList (новый ArrayList ())), являются ли изменения в полученной коллекции гарантией видимости для всех потоков? – user155631

+0

@ user155631 да, это гарантировано, так как доступ к коллекции синхронизируется на внутренних мьютексах. – AdamSkywalker