Volatile Vs Static в java


правильно ли говорить, что static означает одну копию значения для всех объектов и volatile означает одну копию значения для всех потоков?

в любом случае a static значение переменной также будет одним значением для всех потоков, тогда почему мы должны идти на volatile?

7 242

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, немедленно отразится на другом потоке.

в дополнение к другим ответам, я хотел бы добавить одно изображение для него (рис делает легко понять)

enter image description here

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

volatile объявление гарантирует, что потоки не будет кэшировать данные и использует общий доступ копировать только.

Источник изображения

Я думаю static и volatile не имеют никакого отношения вообще. Я предлагаю вам прочитать Java учебник, чтобы понять Атомарный Доступ и зачем использовать атомарный доступ, понять, что такое чередуются, вы найдете ответ.

проще говоря,

  1. статический:static переменные связаны с класс, а не с какой-либо объект. Каждый экземпляр класса имеет общую переменную класса, которая находится в одном фиксированном месте в памяти

  2. летучие: это ключевое слово применимо как класс и экземпляр переменные.

использование изменчивых переменных снижает риск ошибок согласованности памяти, поскольку любая запись в изменчивую переменную устанавливает связь "происходит до" с последующим чтением этой же переменной. Это означает, что изменения изменчивой переменной всегда видны другим потокам

взгляните на это статьи by Javin Paul чтобы понять volatile переменные в лучшую сторону.

enter image description here

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

здесь variable может быть static (класса) переменных или instance (объект) переменной.

относительно вашего запроса :

в любом случае значение статической переменной также будет одним значением для всех потоков, тогда почему мы должны идти на volatile?

если мне понадобится instance переменной в моем приложении, я не могу использовать static переменной. Даже в случае static переменная, согласованность не гарантируется из-за кэша потоков, как показано на диаграмме.

используя volatile переменные снижает риск ошибок согласованности памяти, потому что любая запись в volatile-переменную устанавливает отношение "происходит до" с последующим чтением этой же переменной. Это означает, что изменения изменчивой переменной всегда видны другим потокам.

более того, это также означает, что когда поток читает переменную volatile, он видит не только последнее изменение volatile, но и побочные эффекты кода, которые привели к изменению => ошибки согласованности памяти все еще возможны с изменчивыми переменными. Чтобы избежать побочных эффектов, вы должны использовать синхронизированные переменные. Но есть лучшее решение в Java.

использование простого атомарного доступа к переменным более эффективно, чем доступ к этим переменным через синхронизированный код

некоторые классы java.util.concurrent пакет предоставляет атомарные методы, которые не зависят от синхронизации.

относятся к этому управление параллелизмом высокого уровня статьи новые подробности.

особенно посмотрите на атомарные переменные.

связанные вопросы SE:

Volatile Vs Atomic

Volatile boolean vs AtomicBoolean

разница между volatile и synchronized в Java

доступ к изменчивым переменным будет осуществляться непосредственно из основной памяти. Он должен использоваться только в многопоточной среде. статическая переменная будет загружена один раз. Если он используется в среде с одним потоком, даже если копия переменной будет обновлена и не будет никакого вреда для доступа к ней, поскольку есть только один поток.

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

Если вы ожидаете желаемых результатов от статической переменной, то используйте volatile со статикой в многопоточности, тогда все будет решено.

Если мы объявим переменную как статическую, будет только одна копия переменной. Таким образом, всякий раз, когда разные потоки обращаются к этой переменной, для переменной будет только одно конечное значение(поскольку для переменной выделено только одно место памяти).

Если переменная объявлена как volatile, все потоки будут иметь свою собственную копию переменной, но значение берется из основного memory.So, значение переменной во всех потоках будет следующим тот же.

Итак, в обоих случаях главное заключается в том, что значение переменной одинаково во всех потоках.