2012-03-08 4 views
2

Этот свободный, как класс, не является строго неизменным, потому что поля не являются окончательными, но является ли он потокобезопасным и почему?Безопасность потока свободного класса, использующего clone() и не окончательные поля

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

public class IsItSafe implements Cloneable { 

    private int foo; 
    private int bar; 

    public IsItSafe foo(int foo) { 
     IsItSafe clone = clone(); 
     clone.foo = foo; 
     return clone; 
    } 

    public IsItSafe bar(int bar) { 
     IsItSafe clone = clone(); 
     clone.bar = bar; 
     return clone; 
    } 

    public int getFoo() { 
     return foo; 
    } 

    public int getBar() { 
     return bar; 
    } 

    protected IsItSafe clone() { 
     try { 
      return (IsItSafe) super.clone(); 
     } catch (CloneNotSupportedException e) { 
      throw new Error(e); 
     } 
    } 
} 
+0

Вы можете сделать это немного безопаснее, сделав IsItSafe окончательным.Вы беспокоитесь о том, что кто-то меняет foo или bar с отражением? Почему вас беспокоит их видимость? – alpian

+0

Я не беспокоюсь о том, что кто-то модифицирует поле через отражение или расширяет класс. Я спрашиваю, потому что я разработал аналогичный класс, и его безопасность потока была поставлена ​​под сомнение. –

+0

FYI, я разместил продолжение вопроса здесь: http://stackoverflow.com/questions/9633771/how-can-one-break-this-non-thread-safe-object – assylias

ответ

1

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

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

Некоторые дополнительные пояснения здесь: https://stackoverflow.com/a/9633968/136247

Обновление в вопросе об использовании энергозависимой:

Ради аргумента, используя Летучие устраняет проблему потоковую здесь.
Однако следует пересмотреть конечные поля и конструктор копирования, потому что:

  • доступ Поля будет немного быстрее (чтения всегда может прийти из кэша процессора)
  • Вы избегаете обескуражено использования clone (см Эффективных Java Джош Блох)
  • застройщика с конечными полями известной идиомы для неизменяемых классов и будет легко узнаваем читателями кода
  • маркировки полого volatile, а намереваясь для них незыблемых этого противоречия и I tself;)
+0

Да, но с логической точки зрения это –

+0

Я не уверен, что вы подразумеваете под * logical *. Вы имеете в виду * практически *? Или вы имеете в виду, если не было Java Memory Model, и это был псевдокод? – Joe23

+0

Таким образом, маркировка полей как изменчивых будет устранять проблему видимости, не так ли? –

1

Это thread довольно единодушны в том, что класс не поточно из-за проблем видимости.

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

Единственное место, где изменяются параметры foo и bar (в методах foo() и bar()), изменения выполняются для локальной переменной, которая по определению доступна только по одному потоку за раз.

EDIT

Я думаю, что это пример стека конфайнмента, как это определено в Java Параллелизм на практике (3.3.2), что делает Foo() и бар() методы Потокобезопасная потому clone не позволили избежать метода до его полной сборки.

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

+0

Вот что я думаю, но у меня есть сомнения. Если экземпляр, возвращаемый foo() или bar(), используется совместно с другим потоком, увидит ли оно обновленное значение для bar или foo? –

+3

Downvoter? Позаботьтесь об этом? – assylias

+1

(Я не являюсь нисходящим.) Что касается вашего непреложного аргумента: вы рассматривали переупорядочение инструкций? Если то, что вы здесь говорите, было правильным, не было бы необходимости в том, чтобы последний модификатор создавал потокобезопасные неизменяемые объекты. Что касается аргумента удержания стека: локальная переменная стека 'clone'. Проблема видимости касается полей 'foo' и' bar', которые явно не являются стек-локальными. – Joe23

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