Почему переменные в Java не являются нестабильными по умолчанию? - PullRequest
12 голосов
/ 13 июня 2009

Возможно, похожий вопрос:

Вы когда-нибудь использовали ключевое слово volatile в Java?


Сегодня я отлаживал свою игру; У него была очень трудная проблема с многопоточностью, которая появлялась каждые несколько минут, но ее было трудно воспроизвести. Итак, сначала я добавил ключевое слово synchronized к каждому из моих методов. Это не сработало. Затем я добавил ключевое слово volatile в каждое поле. Проблема, казалось, просто исправилась.

После некоторых экспериментов я обнаружил, что ответственным полем был объект GameState, который отслеживал текущее состояние моей игры, которое может быть либо занятым, либо занятым. Когда занято, игра игнорирует пользовательский ввод. У меня был поток, который постоянно менял переменную state, в то время как поток событий считывал переменную state. Однако после того, как один поток изменяет переменную, другому потоку требуется несколько секунд, чтобы распознать эти изменения, что в конечном итоге вызывает проблему.

Это было исправлено с помощью переменной состояния volatile.

Почему в Java переменные volatile не являются переменными по умолчанию и в чем причина не использовать ключевое слово volatile?

Ответы [ 6 ]

32 голосов
/ 13 июня 2009

Короче говоря, изменчивые переменные - будь то в Java или C # - никогда не кэшируются локально в потоке. Это не имеет большого значения, если вы не имеете дело с многопроцессорным / многоядерным процессором с потоками, выполняющимися на разных ядрах, так как они будут смотреть на один и тот же кеш. Когда вы объявляете переменную как volatile, все операции чтения и записи выполняются прямо и направляются прямо в текущую область основной памяти; там нет кеша Это имеет значение, когда речь заходит об оптимизации, и делать это без необходимости (когда большинству переменных не нужно быть волатильными) означало бы снижение производительности (мизерно, как это может или не может быть) для относительно небольшого выигрыша.

10 голосов
/ 13 июня 2009

Volatiles действительно нужны только тогда, когда вы пытаетесь написать низкоуровневый потокобезопасный, свободный от блокировки код. Большая часть вашего кода, вероятно, не должна быть или поточно-безопасной или без блокировки. По моему опыту, программирование без блокировки стоит попробовать только после того, как вы обнаружили, что более простая версия, которая делает блокировку, вызывает значительное снижение производительности из-за блокировки.

Более приятная альтернатива - использовать другие строительные блоки в java.util.concurrent, некоторые из которых не имеют блокировки, но не так сильно портят голову, как попытка сделать все это самостоятельно на низком уровне. *

Волатильность имеет свои собственные издержки производительности, и нет никаких причин, по которым большинство кодов должны нести эти затраты.

8 голосов
/ 13 июня 2009

Лично я считаю, что поля должны были быть окончательными по умолчанию и быть изменяемыми только с дополнительным ключевым словом, но эта лодка уже давно поплыла. ;)

6 голосов
/ 13 июня 2009

В то время как другие правы, указав, почему было бы плохой идеей по умолчанию использовать volatile, есть еще один момент, который нужно сделать: очень вероятно, что в вашем коде есть ошибка. Переменные редко нужно делать изменчивыми: всегда есть способ правильно синхронизировать доступ к переменным (либо по синхронизированному ключевому слову, либо с использованием объектов AtomicXxx из java.util.concurrency): исключения включают в себя код JNI, манипулирующий ими (который не связан синхронизацией директивы).

Так что вместо добавления volatile вы можете выяснить, ПОЧЕМУ это решило проблему. Это не единственный способ решить эту проблему, и, вероятно, есть лучший способ.

5 голосов
/ 13 июня 2009

Поскольку компилятор не может оптимизировать изменчивые переменные.

volatile сообщает компилятору, что переменная может измениться в любое время. Следовательно, нельзя предполагать, что переменная не изменится и не оптимизируется соответственно.

2 голосов
/ 13 июня 2009

Объявление переменных переменными обычно оказывает огромное влияние на производительность. На традиционных однопоточных системах было относительно легко узнать, что должно быть нестабильным; это были те вещи, которые получили доступ к оборудованию.

В многопоточном режиме это может быть немного сложнее, но я бы вообще рекомендовал использовать уведомления и очереди событий для обработки передачи данных между тэдами в обход магических переменных. В Java это может не иметь большого значения; в C / C ++ вы можете столкнуться с проблемами, когда эти переменные не могут быть установлены атомарно базовым оборудованием.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...