#java #многопоточность #concurrency
Когда можно использовать volatile, если он не обеспечивает атомарность чтения и записи как Atomic'и. Мне не понятно в чем разница между volatile и synchronized, если и то и другое обеспечивает синхронизацию между кэшами ядер процессора.
Ответы
Ответ 1
Модификатор volatile гарантирует видимость операций с полем и сохранение их последовательности. Волатильную переменную можно, например, использовать как флаг завершения работы потока: public class Main { private static volatile boolean run = true; public static void main(String[] args) throws Exception { new Thread(() -> { long x = 0; while (run) { System.out.println(++x); try { Thread.sleep(1000); } catch (InterruptedException exc) {} } }).start(); Scanner scanner = new Scanner(System.in); while (run) { String line = scanner.nextLine(); if ("exit".equals(line)) run = false; } } } Без модификатора volatile у вас нет гарантии, что поток выводящий значения переменной x когда-нибудь заметит, что главный поток изменил состояние переменной run. Синхронизация гарантирует видимость операций, сохранение их последовательности и атомарность. public class Main { private static int x = 0; private static int y = 1000; private static synchronized void transfer() { ++x; --y; } public static void main(String[] args) throws Exception { for (int a = 0; a < 10; a++) { new Thread(() -> { for (int b = 0; b < 100; b++) { transfer(); } }).start(); } System.out.println(x); System.out.println(y); } } Без модификатора synchronized у вас нет гарантии, что значение переменной x будет увеличено на столько же, на сколько уменьшено значение переменной y, так как порядок и продолжительность выполнения потоков непредсказуемы. Во втором примере volatile не поможет. В первом может помочь использование синхронизации, но тогда на каждой итерации один из потоков будет блокировать мьютекс, а второй потом будет останавливаться, пока мьютекс не будет освобождён. Это существенно медленнее проверки состояния волатильной переменной.Ответ 2
Вам почти правильно ответили. Только оптимизации несколько другого рода. Дело в том, что переменная может быть закеширована для более быстрого доступа. Вариантов куча где именно. Например она может быть закеширована для каждого процессора отдельно, может быть закеширована в потоке, в принципе это зависит от того, какая реализация JVM используется. Volatile просто запрещает подобное кэширование. Теперь как его использовать. Volatile работает быстрее, потому что никаких блокировок не происходит. В этом его преимущество перед synchronized. Работа со ссылками атомарна, поэтому там в теории это может быть актуальным. А так да, конструкция относительно редкая, обычно при многопоточности используется что-то специфическое, дабы упростить работу с ней. UPD. Там "на заборах" пишут, что long и double которые не обязательно атомарные, становятся атомарными с volatile. Но официального подтверждения я этому не нашел, если у кого то есть точная информация по этому поводу, будет круто
Комментариев нет:
Отправить комментарий