Потокобезопасность свободно-подобного класса с использованием clone () и не финальных полей - PullRequest
2 голосов
/ 08 марта 2012

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

Меня беспокоит проблема безопасности потоков - это не состояние гонки, а видимость переменных. Я знаю, что есть обходной путь, использующий конечные переменные и конструктор вместо 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);
        }
    }
}

Ответы [ 2 ]

1 голос
/ 08 марта 2012

Вы не держите Блокировку во время установки поля, и, как вы упоминаете, поле не является окончательным.

Поэтому с точки зрения видимости этот подход не является поточно-ориентированным.

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

Обновление, касающееся вопроса об использовании volatile:

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

  • Доступ к полям будет несколько быстрее (чтение всегда может происходить из кэша процессора)
  • Вы избегаете нежелательного использованияclone (см. «Эффективная Java» Джоша Блоха)
  • Конструктор с конечными полями является известной идиомой для неизменяемых классов и легко распознается читателями кода
  • Пометка полей volatile в то времянамерение сделать их неизменными - само по себе противоречие;)
1 голос
/ 08 марта 2012

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

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

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

EDIT

Я думаю, что это пример ограничения стека, как определено в Java Concurrency in Practice (3.3.2), который делает методы foo () и bar () потокобезопасными, потому что clone не разрешается экранировать метод раньше будучи полностью построенным.

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

...