Синхронизация потоков JAVA (разные стеки) - PullRequest
5 голосов
/ 31 декабря 2011

У меня есть вопрос относительно синхронизации кода, который выполняется несколькими потоками:

Насколько я знаю, каждый поток имеет свой собственный стек, следовательно, нестатические переменные существуют в разных местах в памяти для каждого потока (для потоков X есть X стеков, которые включают все нестатические переменные). Так почему нужно что-то синхронизировать?

Я имею в виду, что если код, выполняемый потоками, содержит некоторую переменную класса v1, то каждый поток имеет свой собственный «экземпляр» v1 (другой адрес памяти), и никакой другой поток не может «дотронуться» до него ... isn ' не так ли?

Ответы [ 8 ]

7 голосов
/ 01 января 2012

нестатические переменные существуют в разных местах в памяти для каждого потока

Это не так, поэтому ответ на

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

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

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

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

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

локальное распределение потоков

Если бы распределитель был действительно реализован, как показано в листинге 1, общее поле heapStart быстро стало бы существенным узким местом параллелизма, поскольку каждое распределение включало бы получение блокировки, которая защищает это поле.Чтобы избежать этой проблемы, большинство JVM используют локальные блоки распределения потоков, где каждый поток выделяет больший кусок памяти из кучи и обслуживает небольшие запросы выделения последовательно из этого локального блока потока.В результате число раз, когда поток должен получить блокировку общей кучи, значительно уменьшается, улучшая параллелизм.

* - возможно, оптимизации JVM позволят некоторым объектам выделяться в стеке .

3 голосов
/ 01 января 2012

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

2 голосов
/ 31 декабря 2011

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

2 голосов
/ 31 декабря 2011

В стеке гарантированно выделяются только примитивные типы, такие как int.Все объекты и массивы обычно хранятся в куче, если только Escape Analysis не определит, что область объекта ' ограничена областью действия '.

1 голос
/ 31 декабря 2011

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

1 голос
/ 31 декабря 2011

На том же экземпляре объекта , если ваш метод не синхронизирован, нет гарантии, что один и тот же код не будет выполнен дважды в разных потоках -> хаос!Какое правильное значение?

Как минимум, вы хотите объявить методы, обращающиеся к переменной, как синхронизированные.Если вы хотите более детальное управление, вы можете использовать, например, ReentrantReadWriteLock.

Объявление метода синхронизированных синхронизаций на экземпляре объекта, так что это безопасно.

0 голосов
/ 01 января 2012

«Нестатические переменные существуют в разных местах» не могут быть правильными. В Java вы никогда не узнаете ничего о «стеке». Все ваши переменные класса, статические или экземпляры, происходят из кучи. Однако, как Java-разработчик, вас это не волнует.

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

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

Nrj получил правильную идею.

0 голосов
/ 01 января 2012

Некоторые ключевые моменты, которые могут помочь прояснить ваши сомнения -

  1. Объекты всегда располагаются в куче.

  2. Переменные уровня класса совместно используются между потоками (поток одного и того же объекта)

  3. Локальные переменные всегда являются потокобезопасными (если они не доступны внешнему миру без поточной защиты)

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