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

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();
                }
            }
        }
    }
Комментарии (16)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Vitaly Khant Уровень 0
28 декабря 2018
volatile используется для того, чтобы в цикле какого-то кода опрашивать переменную на наличие изменения из другого потока (как в твоем примере). Больше этот модификатор ничего полезного не несет. Бывают случаи, когда в этом цикле значение переменной считывается постоянно с кеша (в твоём случае повезло, и после sleep'a потоки всё же считали актуальное значение из памяти). Чтобы заставить всё время считывать значение переменной из памяти, используется volatile. Например, если твой метод run заменить этим:

    @Override
    public void run()
    {
        while (!isCancel) {}
        System.out.println("Thread end");
    }
предварительно убрав модификатор volatile, то твои два потока просто зависнут, т.к. значение они постоянно будут брать с кеша, а там находится isCancel = false
Andrei_98 Уровень 31
29 мая 2017
В верхнем примере разве в цикле должно быть true? мне кажется что !this.isCancel
MrBaseMax Уровень 41
7 февраля 2015
И все же есть простые примеры, показывающие, как работает 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% решает проблему. Даже если процессору запрещено хранить в кэше эту переменную, существует небольшая вероятность конфликта данных, пока процессор считывает, меняет и возвращает ее обратно. В лекциях еще будет об этом.
dimaMJ Уровень 25
7 февраля 2015
Help :)