dimaMJ
25 уровень
Craiova

Volatile (пример в 17 лекции)

Пост из группы Архив info.javarush.ru
3261 участников
Вообщем есть в лекции 17 пример c volatile, там сказано, если у переменной isCancel не использовать volatile то изменяя значения данной переменной из другой нити остальные о нем не узнают, я переписал пример, только в методе run происходит вывод имени потока и значения isCancel и получилось так, что у независимо от того, будет ли стоять у переменной volatile или не будет, значение всеравно меняется для всех поток, хоть стукните но я запутался окончательно, если с синхронизацией я разобрался, то с volatile я запутался и не могу его никак применить. Может я как то не так пример создал? Я пробовал еще создать класс Clock и унаследовать от Thread, а в main создать два экземпляра и оба запустить, так же volatile не работал,помогите иначе я сойду сума ) public static void main(String[] args) { Clock n = new Clock(); Thread thread1 = new Thread(n); Thread thread2 = new Thread(n); thread1.start(); thread2.start(); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } n.cancel(); } public static class Clock implements Runnable { private volatile boolean isCancel = false; public void cancel() { this.isCancel = true; } @Override public void run() { while (true) { try { System.out.println(Thread.currentThread().getName()+" "+isCancel); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
Комментарии (15)
  • популярные
  • новые
  • старые
Для того, что бы оставить комментарий вы должны авторизироваться
Andrei_98 31 уровень
29 мая 2017, 15:09
В верхнем примере разве в цикле должно быть true? мне кажется что !this.isCancel
MrBaseMax 41 уровень, Москва
7 февраля 2015, 20:21
И все же есть простые примеры, показывающие, как работает volatile:

public class VolatileDemo {

    public static void main(String[] args) {
        new VolatileDemo().start();
    }
    //----------------------------------------------

    volatile private boolean btExit = false; //попробуйте убрать volatile

    // запуск потоков
    public void start() {
        new Thread(gui).start();
        System.out.println("gui thread started");
        new Thread(game).start();
        System.out.println("game thread started");
    }

    // поток для интерфейса
    Runnable gui = new Runnable() {
        @Override
        public void run() {
            try {
                Thread.sleep(2000); // типа пользователь общается с GUI и выходит из игры
            } catch (InterruptedException ignored) {}
            btExit = true; // поток game не видит это изменение без volatile
            System.out.println("gui thread finished");
        }
    };

    // поток для игры
    Runnable game = new Runnable() {
        @Override
        public void run() {
            while (!btExit) {
                // без volatile этот цикл крутится бесконечно
            }
            System.out.println("game thread finished");
        }
    };
}


И важно помнить, что volatile не на 100% решает проблему. Даже если процессору запрещено хранить в кэше эту переменную, существует небольшая вероятность конфликта данных, пока процессор считывает, меняет и возвращает ее обратно. В лекциях еще будет об этом.
Sdu 17 уровень
7 февраля 2015, 20:30
Спасибо =)
maximushka 36 уровень
8 февраля 2017, 21:24
Я понял что дело в пустом цикле… где // без volatile этот цикл крутится бесконечно
если в цикл поставить sleep или yield или другую команду связанную с текущим потоком… демонстрационный эффект пропадёт. Если можете что-то уточнить, добавить теорию, то с интересом выслушаю.
albaslug 40 уровень, Санкт-Петербург
13 августа 2017, 14:15
Еще интересное поведение. Если убрать volatile для переменной, но в пустом цикле добавить пустой synchronized-блок, т. е. строчку
synchronized (this) {}

то нить будет завершаться так же, как с volatile, через две секунды.
Объясняется здесь (http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#synchronization):
After we exit a synchronized block, we release the monitor, which has the effect of flushing the cache to main memory, so that writes made by this thread can be visible to other threads. Before we can enter a synchronized block, we acquire the monitor, which has the effect of invalidating the local processor cache so that variables will be reloaded from main memory.
Vikentsi 22 уровень, Минск
13 сентября 2017, 19:39
У в любом случае с volatile и без ее программа завершается и строчка gui thread finished на консоль выводится. В чем дело?
maksimys87 38 уровень
25 сентября 2017, 19:42
Так все верно. Строчка gui thread finished выводится. А вот строчка game thread finished не выводится. И программа не завершается. У тебя была такая строчка в консоли Process finished with exit code 0? ))
Lanfirus 26 уровень, Киев
30 января, 21:55
Чтобы эффект volatile перестал действовать достаточно использовать простые команды типа System.out.print(), Thread.sleep() и т.д. Хотя и далеко не все команды выводят программу из цикла. Явно выполнение каких-то действий в цикле приводит к обновлению кэша у второй нити, она видит измененное значение переменной для выхода и завершает работу.
dimaMJ 25 уровень, Craiova
7 февраля 2015, 16:35
Help :)
Sdu 17 уровень
7 февраля 2015, 16:49
Если я Вас правильно понял, то смысл volatile как раз-таки в противоположном.
Без volatile: каждый поток может владеть кэшированным значением переменной, при изменении значения самой переменной поток может об этом и не узнать. Т.е. к примеру Ваша переменная стала true, а поток до сих пор оперирует предыдущим значением false.
С volatile: Запрещается кэширование значения переменной. Каждый поток имеет доступ непосредственно к актуальному значению. В случае изменения, все потоки будут оперировать актуальными данными. Из минусов — относительное снижение скорости доступа к переменной, для нас пока абсолютно не критичное.
dimaMJ 25 уровень, Craiova
7 февраля 2015, 16:54
это я знаю, но в ходе примера, который выше, без volatile, поток знает что изменилась переменная, может как то не так пример сделан? Все что я хотел сделать это на практике увидеть работу volatile
Sdu 17 уровень
7 февраля 2015, 17:07
Ну если Вы внимательно читали лекцию, то наверняка заметили фразу: " И тогда может возникнуть проблема". Никто не говорит, что в данном случае, без volatile, будет обязательно так. Вы можете работать без volatile и никогда не заметить проблемы. Все зависит от java-машины (как распределит потоки, в какой последовательности запустит), аппаратной платформы (например, кол-ва ядер в системе), ОС и случая =) Поэтому, однозначного примера явно демонстрирующего проблему нет.
dimaMJ 25 уровень, Craiova
7 февраля 2015, 17:12
даже так) понятно, спасибо ) а я тут пытаюсь 2 часа создать проблему которую volatile может решить ахах, это я так понимаю мера предосторожности)
Sdu 17 уровень
7 февраля 2015, 17:25
Ну как мера предосторожности… Если JVM разнесет два потока по разным ядрам, а у каждого ядра свой собственный кэш, то проблема становится вполне реальной.
dimaMJ 25 уровень, Craiova
7 февраля 2015, 17:36
понятно спасибо)