Где использовать volataile

174
30 марта 2018, 12:35
  1. Когда можно использовать volataile, если он не обеспечивает атомарность чтения и записи как Atomicи.
  2. Мне не понятно в чем разница между volatile и synchronized, если и то и другое обеспечивает синхронизацию между кэшами ядер процессора.
Answer 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 не поможет. В первом может помочь использование синхронизации, но тогда на каждой итерации один из потоков будет блокировать мьютекс, а второй потом будет останавливаться, пока мьютекс не будет освобождён. Это существенно медленнее проверки состояния волатильной переменной.

Answer 2

Вам почти правильно ответили. Только оптимизации несколько другого рода. Дело в том, что переменная может быть закеширована для более быстрого доступа. Вариантов куча где именно. Например она может быть закеширована для каждого процессора отдельно, может быть закеширована в потоке, в принципе это зависит от того, какая реализация JVM используется.

Volatile просто запрещает подобное кэширование.

Теперь как его использовать. Volatile работает быстрее, потому что никаких блокировок не происходит. В этом его преимущество перед synchronized.

Работа со ссылками атомарна, поэтому там в теории это может быть актуальным.

А так да, конструкция относительно редкая, обычно при многопоточности используется что-то специфическое, дабы упростить работу с ней.

UPD. Там "на заборах" пишут, что long и double которые не обязательно атомарные, становятся атомарными с volatile. Но официального подтверждения я этому не нашел, если у кого то есть точная информация по этому поводу, будет круто

Answer 3

volatile- это не атомарность, а просто переменная, которую компилятор не должен оптимизировать.
Например, вот вам код:

int val = 16;
val = val << 1;
val = val >> 1;

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

UPDATE:

Компилятор старается оптимизировать весь код таким образом, что-бы он был более эфективным. В случае с примером там производится две операции, взаимно-исключающие друг друга. Тоесть сначала происходит сдвиг значения 16 в лево на один бит (получилось 32), потом идет сдвиг 32-х в право на один бит (получилось снова 16). Таким образом, если переменная val, не указазана как volatile, то компилятор просто не делает этих двух сдвигов - для него будто бы ничего не происходит, а значит лишние операции. Но в разработке встраиваемых систем это может быть переключение ножки, для включение какого-то дгугого элемнета - вот там и используют volatile.

READ ALSO
CompletableFuture использует Supplier вместо Callable?

CompletableFuture использует Supplier вместо Callable?

Почему completableFuture использует вместо привычного callable supplier, зачем так путать людей привыкших к старому доброму callable?

183
Java sqlite jdbc и другое

Java sqlite jdbc и другое

Собрал в jar проект, который работает с файлами sqlite (выполняется просто запрос "select id from user")На компьютере, где все собирал, все прекрасно работает

127
Чтение массива чисел

Чтение массива чисел

Есть InputStream в котором записана последовательность известной длины 32 битных чисел в LittleEndian порядке байт

152