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, значение переменной во всех потоках будет следующим тот же.
Итак, в обоих случаях главное заключается в том, что значение переменной одинаково во всех потоках.