Неизменяемые объекты являются потокобезопасными, но почему? - PullRequest
21 голосов
/ 16 февраля 2012

Если один поток создает заполненную ссылочную переменную неизменяемого класса путем создания своего объекта, а во второй раз запускается другой поток до завершения первого потока и создает другой объект неизменяемого класса, не будет ли неизменяемый классиспользование быть потоком небезопасно?Создание неизменяемого объекта также говорит о том, что все поля, помеченные как окончательные как ..... «может потребоваться обеспечить правильное поведение, если ссылка на вновь созданный экземпляр передается из одного потока в другой без синхронизации». Они пытаютсяскажем, что другой поток может перенаправить ссылочную переменную на какой-то другой объект неизменяемого класса и что потоки будут указывать на другие объекты, оставляя состояние несовместимым?

Ответы [ 7 ]

14 голосов
/ 17 февраля 2017

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

Confused ?? ты не должен быть: -

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

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

Когда мы делаем код, мы оцениваем любые изменения в объекте только с помощью ссылки.

Заявление 1: String str = "123"; // изначально строка разделяется на два потока

Заявление 2: str = str + "FirstThread"; // выполняется потоком один

Заявление 3: ул = СИЛ + "SecondThread"; // выполняется потоком два

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

  1. Load Statement2, поэтому str = "123" + "FirstThread"
  2. Load Statement3, поэтому str = "123" + "SecondThread"
  3. Store Statement3, поэтому str = "123SecondThread"
  4. Store Statement2, поэтому str = "123FirstThread"

и, наконец, значение в ссылке str = "123FirstThread" и на некоторое время, если мы предположим, что, к счастью, наш поток GC спит, наши неизменяемые объекты все еще существуют нетронутыми в пуле строк.

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

9 голосов
/ 16 февраля 2012

Неизменяемые объекты являются поточно-ориентированными, но почему?

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

Еслиодин поток создает заполнение ссылочной переменной неизменяемого класса, создавая его объект, а во второй раз запускается другой поток до завершения первого потока и создает другой объект неизменяемого класса, не будет ли использование неизменного класса небезопасным для потока?

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

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

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

7 голосов
/ 16 февраля 2012

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

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

6 голосов
/ 16 февраля 2012

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

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

  • Если флаг равен false, тогда я печатаю «false» изатем я устанавливаю флаг обратно в true.
  • Если флаг равен true, тогда я печатаю «true», а затем я устанавливаю флаг обратно в false.

Если вы постоянно работаете воднопотоковый цикл, у вас будет детерминированный вывод, который будет выглядеть следующим образом:

false - true - false - true - false - true - false ...

Но, если вы запустилитот же код с двумя потоками, то вывод вашего вывода больше не является детерминированным, причина в том, что поток A может проснуться, прочитать флаг, увидеть, что это ложно, но прежде чем он сможет что-либо сделать, поток B пробуждается ичитает флаг, что тоже неверно !!Так что оба будут выводить false ... И это только один проблемный сценарий, который я могу придумать ... Как видите, это плохо.

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

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

Неизменяемые объекты важны для гарантии того, чтоОбласти приложения, которые, как мы уверены, не нуждаются в обновлении, не обновляются, поэтому мы точно знаем, что у нас не будет проблем с многопоточностью

Возможно, вам будет интересно посмотретьна пару книг:

Это самая популярная: http://www.amazon.co.uk/Java-Concurrency-Practice-Brian-Goetz/dp/0321349601/ref=sr_1_1?ie=UTF8&qid=1329352696&sr=8-1

Но я лично предпочитаю эту: http://www.amazon.co.uk/Concurrency-State-Models-Java-Programs/dp/0470093552/ref=sr_1_3?ie=UTF8&qid=1329352696&sr=8-3

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

0 голосов
/ 15 ноября 2017

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

0 голосов
/ 28 сентября 2015

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

//No setters provided
class ImmutableValue
{

     private final int value = 0;

     public ImmutableValue(int value)
     {
          this.value = value;
     }

     public int getValue()
     {
          return value;
     }
}

public class ImmutableValueUser{
  private ImmutableValue currentValue = null;//currentValue reference can be changed even after the referred underlying ImmutableValue object has been constructed.

  public ImmutableValue getValue(){
    return currentValue;
  }

  public void setValue(ImmutableValue newValue){
    this.currentValue = newValue;
  }

}
0 голосов
/ 16 февраля 2012

Два потока не будут создавать один и тот же объект, поэтому проблем нет.

Что касается «может быть необходимо обеспечить ...», то, что они говорят, это то, что если вы НЕ делаетесделайте все поля окончательными, вы сами должны будете убедиться в правильном поведении.

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