2013-02-26 2 views
3
class MyClass 
{ 
    private static volatile Resource resource; 

    public static Resource getInstance() 
    { 
      if(resource == null) 
         resource = new Resource(); 
      return resource; 
    } 
} 

Здесь, если Ресурс является неизменным классом, безопасно ли написать вышеприведенный код? Как и в java-параллелизме на практике, упоминается, что «безопасность инициализации позволяет правильно сконструированные неизменяемые объекты безопасно распределять по потоку. Таким образом, вышеприведенный код безопасен для написания». (на странице № 349 16.3). Но с этим возможно, если два потока проверили нуль, и они могут продолжить создание объекта, что противоречит инварианту класса (singleton). пожалуйста, объясни. Продолжение вопроса в linksingleton с неизменным классом в java

+2

Этот вопрос есть * так * рядом с вашим [другим вопросом] (http://stackoverflow.com/questions/15077910/singleton-with-volatile-in-java), чтобы волосы подталкивали его в направлении дублирования. – Perception

+0

@Perception Спасибо. Вы говорите, что два потока создадут два разных объекта? – Trying

+0

Умм, нет, я ничего подобного не говорю. Я говорю, что вы могли внести небольшую поправку в свой первоначальный вопрос, чтобы охватить этот крайний сценарий. – Perception

ответ

6

Нет, это нетоновый код. В этом случае Resource может быть потокобезопасным, но ваш метод getInstance не является.

Представьте себе такую ​​последовательность событий

Thread1 calls getInstance and checks "if resource == null" and then stops (because the OS said it was time for it to be done) before initializing the resources. 

Thread2 calls getInstance and checks "if resource == null" and then initializes the instance 

Now Thread1 starts again and it also initializes the instance. 

В настоящее время инициализируется дважды, и не является одноточечным.

У вас есть несколько вариантов, чтобы сделать его потокобезопасным.

  1. Сделать метод getInstance синхронизируется

  2. Инициализировать экземпляр по декларации (или в статическом инициализаторе), и getInstance может просто вернуть его.

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

+0

, то в чем смысл выражения thats дано в java-параллелизме на практике (на странице № 349 16.3). Он отметил, что приведенный выше код действительно безопасен, если ресурс неизменен. – Trying

+0

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

+0

Большое спасибо за ур комментарий. Это означает, что в книге они говорят только о проблеме видимости, но нам также необходимо решить проблему атомарности, поэтому необходима синхронизация. Я прав? Я только начинаю с параллелизма, поэтому иногда мои вопросы могут казаться глупыми. – Trying

Смежные вопросы