Как я понял из статьи «Параллелизм Java на практике», когда один поток изменяет какое-либо значение совместно используемой переменной, нет гарантии, что второй поток увидит это новое значение, если только он не использует ту же блокировку, что и первый поток, перед чтением. (стр. 37, рис. 3.1). Я провел небольшой тест и обнаружил, что каждый раз, когда я меняю какое-то значение var в одном потоке, его видит второй всегда! Без какой-либо синхронизации. Что я ошибаюсь?
Мой код:
public class Application {
public int a = 5;
public int b = 3;
public static void main(String[] args) throws InterruptedException {
final Application app = new Application();
for (int i = 0; i < 20000; i++) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
app.a = 0;
app.b = 0;
}
});
t.start();
t.join();
if (app.a == 5 || app.b==3) System.out.println("Old value!");
app.a = 5;
app.b = 3;
}
}
}
Что-то о том, как вы проводите этот тест пахнет. Я не уверен, что вы тестируете то, что думаете о себе.
1. Вы вызываете join (), который обеспечивает гарантии видимости. Вам нужно попробовать читать, пока поток работает. Не после того, как вы к нему присоединились. Но в любом случае ваша логика ошибочна. Это в основном похоже на «Мне сказали, что ты можешь умереть, если перейдешь дорогу, не посмотрев сначала на машины. Но я делал это 10 раз, и я все еще жив».
Вы присоединились к потоку записи перед чтением переменных, что AFAIK создает барьер памяти с гарантиями видимости.




«Существует без гарантии, что другие потоки будут видят значение» - это не то же самое утверждение, что и «существует гарантия, что другие потоки не будет видят значение». Они могут или не могут, в зависимости от вашей реализации JVM, вашего процессора и положения Венеры по отношению к Сатурну.