Использование логического var для остановки потоков - PullRequest
3 голосов
/ 09 ноября 2011

У меня есть книга по Java, которую я изучаю, и в одном из примеров я увидел что-то подозрительное.

public class ThreadExample extends MIDlet {
    boolean threadsRunning = true; // Flag stopping the threads

    ThreadTest thr1;
    ThreadTest thr2;

    private class ThreadTest extends Thread {
        int loops;

        public ThreadTest(int waitingTime) {
            loops = waitTime;
        }

        public void run() {
            for (int i = 1; i <= loops; i++) {
                if (threadsRunning != true) { // here threadsRunning is tested
                    return;
                }

                try {
                    Thread.sleep(1000);
                } catch(InterruptedException e) {
                    System.out.println(e);
                }
            }
        }
    }

    public ThreadExample() {
        thr1 = new ThreadTest(2);
        thr2 = new ThreadTest(6);
    }

    public void startApp() throws MIDletStateChangeException {
        thr1.start();
        thr2.start();

        try {
            Thread.sleep(4000); // we wait 4 secs before stopping the threads - 
                                // this way one of the threads is supposed to finish by itself
        } catch(InterruptedException e) {
            System.out.println(e);
        }

        destroyApp();
    }

    public void destroyApp() {    
        threadsRunning = false;

        try {
            thr1.join();
            thr2.join();
        } catch(InterruptedException e) {
            System.out.println(e);
        }

        notifyDestroyed();
    }
}

Поскольку это приложение мидлета, при его запуске выполняется метод startApp. Для простоты метод startApp сам вызывает destroyApp, поэтому программа уничтожает, останавливает потоки и уведомляет об уничтожении.

Вопрос в том, безопасно ли использовать эту переменную 'threadsRunning', и будет ли ее использование в обоих потоках и в методе destroyApp вызывать какие-либо проблемы в какой-то момент? Поможет ли ключевое слово «volatile» перед объявлением синхронизировать его?

1 Ответ

6 голосов
/ 09 ноября 2011

Установка логического значения является атомарной, и в этом примере нет логики «читать, затем изменить», поэтому доступ к переменной не нужно синхронизировать в этом конкретном случае.

Однако переменная должна быть по крайней мере помечена как volatile.

Пометка переменной volatile не синхронизирует доступ потоков к ней; он гарантирует, что поток не пропустит обновление другого потока переменной из-за оптимизации кода или кэширования значений. Например, без volatile код внутри run() может прочитать значение threadsRunning только один раз в начале, кэшировать значение и затем использовать это кэшированное значение в операторе if каждый раз вместо чтения переменная снова из основной памяти. Если значение threadsRunning изменяется другим потоком, оно может не быть получено.

Как правило, если вы используете переменную из нескольких потоков и ее доступ не синхронизирован, вы должны пометить ее как энергозависимую.

...