Правильно ли говорить, что это static
означает одну копию значения для всех объектов и volatile
означает одну копию значения для всех потоков?
В любом случае, static
значение переменной также будет одним значением для всех потоков, тогда зачем нам идти volatile
?
Ответы:
Объявление статической переменной в Java означает, что будет только одна копия, независимо от того, сколько объектов класса создано. Переменная будет доступна даже без
Objects
создания вообще. Однако потоки могут иметь локально кэшированные значения этого.Когда переменная изменчива, а не статична , для каждой будет одна переменная
Object
. Таким образом, на первый взгляд, нет никакой разницы от обычной переменной, но она полностью отличается от статической . Однако даже сObject
полями поток может кэшировать значение переменной локально.Это означает, что если два потока одновременно обновляют переменную одного и того же объекта, а переменная не объявляется как volatile, может быть случай, когда один из потоков имеет в кэше старое значение.
Даже если вы обращаетесь к статическому значению через несколько потоков, каждый поток может иметь свою локальную кэшированную копию! Чтобы избежать этого, вы можете объявить переменную как static volatile, и это заставит поток читать каждый раз глобальное значение.
Тем не мение, volatile не заменяет правильную синхронизацию!
Например:
Выполнение
concurrentMethodWrong
одновременно много раз может привести к конечному значению счетчика , отличным от нуля!Чтобы решить проблему, вы должны реализовать блокировку:
Или используйте
AtomicInteger
класс.источник
Разница между статическим и изменчивым:
Статическая переменная : если два потока (предположим ,
t1
иt2
) имеют доступ к той же объект и обновление переменной , которая объявлена как статические , то это означает , чтоt1
иt2
может сделать свою собственную локальную копию одного и того же объекта ( в том числе статические переменные) в их соответствующем кэше, поэтому обновление сделанныйt1
статической переменной в ее локальном кэше, не будет отражаться в статической переменной дляt2
кэша.Статические переменные используются в контексте объекта, где обновление, выполненное одним объектом, будет отражаться во всех других объектах того же класса, но не в контексте потока, где обновление одного потока до статической переменной будет отражать изменения сразу для всех объектов. потоки (в их локальном кэше).
Летучие переменный : если два потока (предположит ,
t1
иt2
) имеют доступ к тому же объекту и обновление переменного , которая объявлена как летучие то это означает , чтоt1
иt2
может сделать свой собственный локальный кэш объекта , за исключением переменного , которая объявлена как летучие . Таким образом, переменная volatile будет иметь только одну основную копию, которая будет обновляться различными потоками, а обновление, выполненное одним потоком для переменной volatile, будет немедленно отражено для другого потока.источник
volatile
переменная может быть разделена между различными кэшами процессора. Это не представляет проблемы, потому что кеш согласовывает исключительное владение строкой кеша до ее изменения.В дополнение к другим ответам, я хотел бы добавить для него одно изображение (рис легко понять)
static
переменные могут быть кэшированы для отдельных потоков. В многопоточной среде, если один поток изменяет свои кэшированные данные, это может не отражаться на других потоках, поскольку они имеют их копию .volatile
Объявление гарантирует, что потоки не будут кэшировать данные и использует только общую копию .источник изображения
источник
Я думаю
static
и неvolatile
имею никакого отношения вообще. Я предлагаю вам прочитать Java-учебник, чтобы понять атомарный доступ , и зачем использовать атомарный доступ, понять, что чередуется , вы найдете ответ.источник
Проще говоря,
статические :
static
переменные связаны с классом , а не с любым объектом . Каждый экземпляр класса совместно использует переменную класса, которая находится в одном фиксированном месте в памятиvolatile : это ключевое слово применимо к переменным класса и экземпляра .
Взгляните на эту статью ,
Javin Paul
чтобы лучше понять переменные переменные.При отсутствии
volatile
ключевого слова значение переменной в стеке каждого потока может отличаться. Делая переменную какvolatile
, все потоки получат одинаковое значение в своей рабочей памяти, и ошибок целостности памяти удалось избежать.Здесь термин
variable
может быть либоstatic
(классом) переменной, либоinstance
(объектной) переменной.По вашему запросу:
Если мне нужно
instance
переменная в моем приложении, я не могу использоватьstatic
переменную. Даже в случаеstatic
переменной согласованность не гарантируется из-за кеша потоков, как показано на диаграмме.Использование
volatile
переменных снижает риск ошибок согласованности памяти, потому что любая запись в энергозависимую переменную устанавливает связь «произойдет до» с последующим чтением этой же переменной. Это означает, что изменения в изменчивой переменной всегда видны другим потокам.Использование простого атомарного доступа к переменным более эффективно, чем доступ к этим переменным через синхронизированный код
Некоторые из классов в
java.util.concurrent
пакете предоставляют атомарные методы, которые не зависят от синхронизации.Обратитесь к этому высокоуровневому контролю параллелизма статье о для получения дополнительной информации.
Особенно взгляните на атомарные переменные .
Связанные вопросы SE:
Летучие против атомных
Летучий логический против AtomicBoolean
Разница между изменчивым и синхронизированным в Java
источник
volatile
раньше, но этот ответ проясняет много для меня , почему я до сих пор нужно использоватьvolatile
сstatic
переменной.доступ к значению переменной переменной будет прямым из основной памяти. Он должен использоваться только в многопоточной среде. Статическая переменная будет загружена один раз. Если он используется в однопоточном окружении, даже если копия переменной будет обновлена и доступ к ней не будет вреден, поскольку существует только один поток.
Теперь, если статическая переменная используется в многопоточной среде, возникнут проблемы, если от нее ожидать желаемого результата. Поскольку каждый поток имеет свою собственную копию, то любое увеличение или уменьшение статической переменной из одного потока может не отражаться в другом потоке.
если ожидаются желаемые результаты от статической переменной, тогда используйте volatile со static в многопоточности, тогда все будет решено.
источник
Не уверен, что статические переменные кэшируются в локальной памяти потока или НЕ. Но когда я выполнил два потока (T1, T2), обращающихся к одному и тому же объекту (obj), и когда обновление, выполненное потоком T1, до статической переменной, это отразилось в T2.
источник
Если мы объявим переменную как статическую, будет только одна копия переменной. Таким образом, всякий раз, когда разные потоки обращаются к этой переменной, для переменной будет только одно конечное значение (поскольку для переменной выделена только одна ячейка памяти).
Если переменная объявлена как volatile, все потоки будут иметь свою собственную копию переменной, но значение будет взято из основной памяти. Так что значение переменной во всех потоках будет одинаковым.
Таким образом, в обоих случаях главное состоит в том, что значение переменной одинаково во всех потоках.
источник