Статические переменные и многопоточность в Java - PullRequest
21 голосов
/ 08 декабря 2011

Является ли статический член класса только одним экземпляром для процесса или потока? Значение означает, что каждый поток имеет свою собственную копию статической переменной-члена класса?

Мое предположение за процесс, я прав?

Ответы [ 7 ]

40 голосов
/ 08 декабря 2011

static поля имеют одно значение на загрузчик классов, но я думаю, что смысл вашего вопроса заключается в следующем:

каждый поток имеет свою собственную копию статической переменной-члена класса

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

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

Вот достойная страница о модели памяти Java и хорошая обзор некоторых проблем .

24 голосов
/ 08 декабря 2011

Статические поля дают одно значение для загрузчика классов.

Если вы хотите значение для каждого потока, сделайте статическое ThreadLocal<T>.

10 голосов
/ 08 декабря 2011

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

Например, когда два веб-приложения объединяют один и тот же класс, класс будет загружен дважды, таким образом, имея две копиитого же поля static.

Если вам нужна переменная, имеющая независимое значение на основе потоков, взгляните на ThreadLocal.

4 голосов
/ 08 декабря 2011

http://docs.oracle.com/javase/tutorial/java/nutsandbolts/variables.html

Переменные класса (статические поля) Переменная класса - это любое поле, объявленное с модификатором static; это говорит компилятору, что существует ровно одна копия этой переменной, независимо от того, сколько раз был создан экземпляр класса. Поле, определяющее число передач для конкретного вида велосипеда, может быть помечено как статическое, поскольку концептуально одинаковое количество передач будет применяться ко всем экземплярам. Код статический int numGears = 6; создаст такое статическое поле. Кроме того, можно добавить ключевое слово final, чтобы указать, что число передач никогда не изменится.

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

2 голосов
/ 04 апреля 2014

Проблема с многопоточностью заключается в следующем: представление на 10 000 футов памяти Java состоит в том, что существует один единственный фрагмент памяти, который используется всеми классами, всеми объектами, всеми загрузчиками классов и всеми потоками в работающей JVM - - все, что доступно из одного места в коде, доступно везде (с соответствующей ссылкой). Единственное исключение составляют регистры и стек выполнения, которые концептуально основаны на потоках.

Это чертовски хорошо работает с одним процессором, где потоки по очереди исполняются в одном наборе регистров, ALU и т.п. Но большинство современных компьютеров имеют несколько процессоров, поэтому несколько потоков могут выполняться буквально одновременно. Если бы все эти процессоры ссылались на одну и ту же физическую память, то (исходя из опыта реальной жизни) вы могли бы получить улучшение производительности примерно в 1,5 раза с 4 процессорами, и это привело бы к вырождению.

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

Решение состоит в том, чтобы установить протоколы, чтобы никакие два процессора не пытались изменить одни и те же места хранения в одно и то же время (или почти одно и то же), а также чтобы гарантировать, что один измененный процессор «сбрасывается» в основное хранилище, а другие процессоры сообщил об изменениях и посоветовал перезагрузить их представление об измененных данных.

Но (невероятно) неэффективно делать это после каждой операции (и, откровенно говоря, разработчики аппаратного обеспечения в значительной степени избежали этой проблемы и перенесли большую часть этой работы на программное обеспечение, чем это, вероятно, оправдано). Таким образом, схемы используются так, что сброс и перезагрузка данных происходит только на определенных «границах» или при выполнении определенных специальных типов ссылок.

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

0 голосов
/ 08 декабря 2011

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

0 голосов
/ 08 декабря 2011

Поскольку SLaks предложил один по одному на JVM, но имейте в виду, что два потока, удерживающие блокировку на одной и той же статической ссылке, будут блокировать друг друга, поскольку существует только одна такая ссылка на vm. Но они не будут блокировать потоки, ссылающиеся на переменные экземпляра.

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