JavaRush/Java блог/Архив info.javarush/Volatile (пример в 17 лекции)
dimaMJ
25 уровень

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

Статья из группы Архив info.javarush
участников
Вообщем есть в лекции 17 пример c volatile, там сказано, если у переменной isCancel не использовать volatile то изменяя значения данной переменной из другой нити остальные о нем не узнают, я переписал пример, только в методе run происходит вывод имени потока и значения isCancel и получилось так, что у независимо от того, будет ли стоять у переменной volatile или не будет, значение всеравно меняется для всех поток, хоть стукните но я запутался окончательно, если с синхронизацией я разобрался, то с volatile я запутался и не могу его никак применить. Может я как то не так пример создал? Я пробовал еще создать класс Clock и унаследовать от Thread, а в main создать два экземпляра и оба запустить, так же volatile не работал,помогите иначе я сойду сума ) Volatile (пример в 17 лекции) - 1
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();
                }
            }
        }
    }
Комментарии (11)
  • популярные
  • новые
  • старые
Для того, чтобы оставить комментарий Вы должны авторизоваться
Vitaly Khant
Уровень 0
28 декабря 2018, 18:29
volatile используется для того, чтобы в цикле какого-то кода опрашивать переменную на наличие изменения из другого потока (как в твоем примере). Больше этот модификатор ничего полезного не несет. Бывают случаи, когда в этом цикле значение переменной считывается постоянно с кеша (в твоём случае повезло, и после sleep'a потоки всё же считали актуальное значение из памяти). Чтобы заставить всё время считывать значение переменной из памяти, используется volatile. Например, если твой метод run заменить этим:
@Override
public void run()
{
    while (!isCancel) {}
    System.out.println("Thread end");
}
предварительно убрав модификатор volatile, то твои два потока просто зависнут, т.к. значение они постоянно будут брать с кеша, а там находится isCancel = false
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
Спасибо =)
Vikentsi
Уровень 22
13 сентября 2017, 19:39
У в любом случае с volatile и без ее программа завершается и строчка gui thread finished на консоль выводится. В чем дело?
dimaMJ
Уровень 25
7 февраля 2015, 16:35
Help :)
Sdu
Уровень 17
7 февраля 2015, 16:49
Если я Вас правильно понял, то смысл volatile как раз-таки в противоположном.
Без volatile: каждый поток может владеть кэшированным значением переменной, при изменении значения самой переменной поток может об этом и не узнать. Т.е. к примеру Ваша переменная стала true, а поток до сих пор оперирует предыдущим значением false.
С volatile: Запрещается кэширование значения переменной. Каждый поток имеет доступ непосредственно к актуальному значению. В случае изменения, все потоки будут оперировать актуальными данными. Из минусов — относительное снижение скорости доступа к переменной, для нас пока абсолютно не критичное.
dimaMJ
Уровень 25
7 февраля 2015, 16:54
это я знаю, но в ходе примера, который выше, без volatile, поток знает что изменилась переменная, может как то не так пример сделан? Все что я хотел сделать это на практике увидеть работу volatile
Sdu
Уровень 17
7 февраля 2015, 17:07
Ну если Вы внимательно читали лекцию, то наверняка заметили фразу: " И тогда может возникнуть проблема". Никто не говорит, что в данном случае, без volatile, будет обязательно так. Вы можете работать без volatile и никогда не заметить проблемы. Все зависит от java-машины (как распределит потоки, в какой последовательности запустит), аппаратной платформы (например, кол-ва ядер в системе), ОС и случая =) Поэтому, однозначного примера явно демонстрирующего проблему нет.
dimaMJ
Уровень 25
7 февраля 2015, 17:12
даже так) понятно, спасибо ) а я тут пытаюсь 2 часа создать проблему которую volatile может решить ахах, это я так понимаю мера предосторожности)
Sdu
Уровень 17
7 февраля 2015, 17:25
Ну как мера предосторожности… Если JVM разнесет два потока по разным ядрам, а у каждого ядра свой собственный кэш, то проблема становится вполне реальной.
dimaMJ
Уровень 25
7 февраля 2015, 17:36
понятно спасибо)