Я не буду пытаться на самом деле ответить на ваши вопросы здесь - вместо этого я перенаправлю вас к книге, которую, как я вижу, рекомендуется для совета по этой теме: Параллелизм Java на практике .
Одно предупреждение: если здесь есть ответов , ожидайте, что многие из них будут неправильными. Одна из причин, по которой я не собираюсь публиковать подробности, заключается в том, что я почти уверен, что я бы ошибся, по крайней мере, в некоторых отношениях. Я имею в виду отсутствие неуважения к сообществу, когда я говорю, что шансы каждого, кто думает, что он может ответить на этот вопрос, на самом деле имея достаточно строгости, чтобы сделать его правильно, практически равны нулю. (Джо Даффи недавно обнаружил некоторую модель памяти .NET, которая была удивлена. Если он может ошибиться, то могут и такие смертные, как мы.)
Я предложу немного понимания только по одному аспекту, потому что его часто неправильно понимают:
Есть разница между волатильностью и атомарностью. Люди часто думают, что атомарная запись является энергозависимой (т. Е. Вам не нужно беспокоиться о модели памяти, если запись атомарна). Это не правда.
Волатильность означает, будет ли один поток, выполняющий чтение (логически, в исходном коде), «видеть» изменения, сделанные другим потоком.
Атомность - это вероятность того, что если изменение будет замечено , будет видна только часть изменения.
Например, взять запись в целочисленное поле. Это гарантированно будет атомным, но не летучим. Это означает, что если у нас есть (начиная с foo.x = 0):
Thread 1: foo.x = 257;
Thread 2: int y = foo.x;
Возможно, что y
будет 0 или 257. Это не будет никаким другим значением (например, 256 или 1) из-за ограничения атомарности. Однако, даже если вы знаете, что во «настенное время» код в потоке 2, выполняемый после кода в потоке 1, может произойти странное кэширование, доступ к памяти «движется» и т. Д. Если сделать переменную x
volatile, то это исправится.
Остальное оставлю на усмотрение настоящих честных экспертов.