Многопоточность ленивая инициализация - PullRequest
0 голосов
/ 29 января 2012

У меня есть вопрос о многопоточности Java.

У меня есть класс, который имеет доступ к нескольким потокам.

Class A 
{
    private Object obj;

    public Object returnObject()
    {
       if(condition)
          return getObjectA();
       else
          return getObjectB();
    }

    public Object getObjectA()
    {
       obj = new Object()
       obj.setProperty("prp1");
    }

    public Object getObjectB()
    {
       obj = new Object()
       obj.setProperty("prp2");
    }
}

Когда несколько потоков обращаются к getObj .. (). Создает ли это проблемы с состоянием obj. Будут ли нежелательные результаты?

Спасибо, Слакс и Питер,

Я думаю, что следующее также решит проблемы безопасности потока:

public Object getObjectA()
{
  Object obj = new Object()
  obj.setProperty("prp1");  
  return obj;                                                                                   
}

Ответы [ 6 ]

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

Да, но это довольно просто исправить, так как вы заменяете obj каждый вызов, вы явно не заботитесь об этом, поэтому попробуйте сделать поле obj просто локальной переменной, например:

Class A {
    public Object returnObject() {
       if (true)
           return getObjectA();
       return getObjectB();
    }

    public Object getObjectA() {
       Object obj = new Object()
       obj.setProperty("prp1");
       return obj;
    }

    public Object getObjectB() {
       Object obj = new Object()
       obj.setProperty("prp2");
       return obj;
    }
}

Если это работает для вас, рассмотрите возможность использования этих методов static.

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

Я бы предложил изменить код на НЕ содержит 'obj' в качестве элемента данных, так как необходимо одновременный доступ к нему.

Существует несколько решений:

  1. Создание объекта локально внутри функций
  2. Используйте объект ThreadLocal, который может "оборачивать" элемент данных 'obj'
  3. Создайте объект один раз, и пользователь clone() для каждого локального вызова локального объекта и отредактируйте его.
0 голосов
/ 29 января 2012

Я думаю, что getObjectA() и getObjectB() должны быть объявлены как частные, и тогда вы должны использовать синхронизированный блок внутри метода returnObject(), так что-то вроде этого:

class A 
{

private Object obj;

public Object returnObject()
{

   Object result;
   synchronized (A.class) { 
   result = (true) ? getObjectA() : getObjectB();
   }
  return result;
}

private Object getObjectA()
{
   obj = new Object()
   obj.setProperty("prp1");
}

private Object getObjectB()
{
   obj = new Object()
   obj.setProperty("prp2");
}

} 

Очевидно, что условие true должно быть заменено некоторым условием ...

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

При условии, что if(true) не является жестко запрограммированным, так как это исправит путь выполнения, где всегда вызывается getObjA ()!

Да, этот код может работать в состоянии гонки, где значение obj может зависеть от порядка выполнения потока (т. Е. От того, какой метод getObj .. () вызывается несколькими потоками).

Вам необходимо synchronize получить доступ к переменной obj.

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

Да, это создаст проблемы (попробуйте код, чтобы увидеть, какие проблемы, но данные будут потеряны). Самое простое решение - использовать блок synchronized.

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

Да.

Если два потока одновременно вызывают разные пути кода в returnObject(), он может запустить getObjectB() между двумя операторами в getObjectA() и в конечном итоге вызвать obj.setProperty("prp1"); для ObjectB.

...