Volatile Vs Static в java
правильно ли говорить, что static означает одну копию значения для всех объектов и volatile означает одну копию значения для всех потоков?
в любом случае a static значение переменной также будет одним значением для всех потоков, тогда почему мы должны идти на volatile?
7 ответов:
объявление a статический переменная в Java, означает, что будет только одна копия, независимо от того, сколько объектов класса создаются. Переменная будет доступна даже без
Objectsсоздаются. Однако потоки могут иметь его локально кэшированные значения.когда переменная летучие, а не статический там будет одна переменная для каждого
Object. Итак, на поверхности кажется, что нет никакой разницы с нормальной переменной, но полностью отличается от статический. Впрочем, даже сObjectполя, поток может кэшировать значение переменной локально.это означает, что если два потока обновляют переменную одного и того же объекта одновременно, и переменная не объявлена изменчивой, может быть случай, когда один из потоков имеет в кэше старое значение.
даже если вы получаете доступ к статический значение через несколько потоков, каждый поток может иметь свою локальную кэшированную копию! Избегать этого вы можете объявить переменную как статический летучих и это заставит поток читать каждый раз глобальное значение.
, летучие не является заменой для надлежащей синхронизации!
Например:private static volatile int counter = 0; private void concurrentMethodWrong() { counter = counter + 5; //do something counter = counter - 5; }выполнения
concurrentMethodWrongодновременно много раз может привести к конечному значению счетчика, отличному от нуля!
Чтобы решить проблему, вы должны выполнить блокировку:private static final Object counterLock = new Object(); private static volatile int counter = 0; private void concurrentMethodRight() { synchronized (counterLock) { counter = counter + 5; } //do something synchronized (counterLock) { counter = counter - 5; } }или использовать
AtomicIntegerкласса.
разница между статическим и летучим :
Статическая Переменная: если два потока(предположим
t1иt2) обращаются к тому же объекту и обновляют переменную, которая объявлена как статическая, тогда это означаетt1иt2может сделать свою собственную локальную копию того же объекта(включая статические переменные) в своем соответствующем кэше, поэтому обновление производитсяt1чтобы статическая переменная в локальном кэше не отражалась в статической переменной дляt2кэш.статические переменные используются в блоке контекст объекта где обновление, сделанное одним объектом, отразилось бы во всех других объектах того же класса но не в контексте потока где обновление одного потока до статической переменной будет отражать изменения сразу для всех потоков (в их локальном кэше).
volatile переменная: если два потока(предположим
t1иt2) получают доступ к тому же объекту и обновление переменной, которая объявлена как volatile, то это значитt1иt2может сделать свой собственный локальный кэш объекта кроме переменной, которая объявлена как volatile . Таким образом, переменная volatile будет иметь только одну основную копию, которая будет обновляться разными потоками, и обновление, выполненное одним потоком для переменной volatile, немедленно отразится на другом потоке.
в дополнение к другим ответам, я хотел бы добавить одно изображение для него (рис делает легко понять)
staticпеременные могут быть кэшированы для отдельных потоков. В многопоточной среде если один поток изменяет его кэшированные данные, которые могут не отражать для других потоков, как они имеют копию его.
volatileобъявление гарантирует, что потоки не будет кэшировать данные и использует общий доступ копировать только.
Я думаю
staticиvolatileне имеют никакого отношения вообще. Я предлагаю вам прочитать Java учебник, чтобы понять Атомарный Доступ и зачем использовать атомарный доступ, понять, что такое чередуются, вы найдете ответ.
проще говоря,
статический:
staticпеременные связаны с класс, а не с какой-либо объект. Каждый экземпляр класса имеет общую переменную класса, которая находится в одном фиксированном месте в памятилетучие: это ключевое слово применимо как класс и экземпляр переменные.
использование изменчивых переменных снижает риск ошибок согласованности памяти, поскольку любая запись в изменчивую переменную устанавливает связь "происходит до" с последующим чтением этой же переменной. Это означает, что изменения изменчивой переменной всегда видны другим потокам
взгляните на это статьи by
Javin Paulчтобы понять volatile переменные в лучшую сторону.в отсутствие
volatileключевое слово, значение переменной в стеке каждого потока может быть разной. Сделав переменную какvolatile, все потоки получат одинаковое значение в их рабочей памяти и ошибки согласованности памяти были исключены.здесь
variableможет бытьstatic(класса) переменных илиinstance(объект) переменной.относительно вашего запроса :
в любом случае значение статической переменной также будет одним значением для всех потоков, тогда почему мы должны идти на volatile?
если мне понадобится
instanceпеременной в моем приложении, я не могу использоватьstaticпеременной. Даже в случаеstaticпеременная, согласованность не гарантируется из-за кэша потоков, как показано на диаграмме.используя
volatileпеременные снижает риск ошибок согласованности памяти, потому что любая запись в volatile-переменную устанавливает отношение "происходит до" с последующим чтением этой же переменной. Это означает, что изменения изменчивой переменной всегда видны другим потокам.более того, это также означает, что когда поток читает переменную volatile, он видит не только последнее изменение volatile, но и побочные эффекты кода, которые привели к изменению => ошибки согласованности памяти все еще возможны с изменчивыми переменными. Чтобы избежать побочных эффектов, вы должны использовать синхронизированные переменные. Но есть лучшее решение в Java.
использование простого атомарного доступа к переменным более эффективно, чем доступ к этим переменным через синхронизированный код
некоторые классы
java.util.concurrentпакет предоставляет атомарные методы, которые не зависят от синхронизации.относятся к этому управление параллелизмом высокого уровня статьи новые подробности.
особенно посмотрите на атомарные переменные.
связанные вопросы SE:
доступ к изменчивым переменным будет осуществляться непосредственно из основной памяти. Он должен использоваться только в многопоточной среде. статическая переменная будет загружена один раз. Если он используется в среде с одним потоком, даже если копия переменной будет обновлена и не будет никакого вреда для доступа к ней, поскольку есть только один поток.
теперь, если статическая переменная используется в многопоточной среде, то будут проблемы, если вы ожидаете от нее желаемого результата. Так как каждая нить имеет свои собственная копия тогда любое приращение или уменьшение статической переменной из одного потока может не отражаться в другом потоке.
Если вы ожидаете желаемых результатов от статической переменной, то используйте volatile со статикой в многопоточности, тогда все будет решено.
Если мы объявим переменную как статическую, будет только одна копия переменной. Таким образом, всякий раз, когда разные потоки обращаются к этой переменной, для переменной будет только одно конечное значение(поскольку для переменной выделено только одно место памяти).
Если переменная объявлена как volatile, все потоки будут иметь свою собственную копию переменной, но значение берется из основного memory.So, значение переменной во всех потоках будет следующим тот же.
Итак, в обоих случаях главное заключается в том, что значение переменной одинаково во всех потоках.

