Существует ли проблема с защитой потока или видимости с использованием поля «private static» вместо поля «private final static»

1

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

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

Пример статического поля:

public class Singleton {

    private static Singleton instance = new Singleton();

    public static Singleton getInstance() {
        return instance;
    }

    private Singleton() {
    }
}

Пример конечного статического поля:

public class Singleton_final {

    private final static Singleton instance = new Singleton();

    public static Singleton getInstance() {
        return instance;
    }

    private Singleton() {
    }
}

С наилучшими пожеланиями, Германн

  • 0
    Не делай ни; если вам нужен синглтон, используйте enum .
  • 0
    @ user2357112: Если то, что вы хотите, это действительно Enum. В противном случае, не используйте Singleton.
Показать ещё 1 комментарий
Теги:
thread-safety
singleton
visibility

2 ответа

1
Лучший ответ

Как и во многих проблемах многопоточности, это немного тонко. Позвольте мне немного разобраться в этом вопросе, а затем дать вам ответ.

Уточнение вопроса

Если клиент видит null ссылку non-, они будут видеть только один Singleton вы создаете. На этом нет вопросов. Вот два вопроса:

  • возможно ли, чтобы кто-нибудь увидел null?
  • возможно ли кому-то увидеть частично построенный Singleton?

Последний вопрос не совсем уместен для вашего дела, потому что у Singleton нет никакого состояния. Но если у него было состояние, и это состояние было сохранено в non- final полях, то это было бы проблемой. Например, учитывая:

public class Singleton {
    private /* non-final */ String name;

    private Singleton(String name) {
        this.name = name;
    }
}

... частично построенный Singleton - это тот, чье имя равно null (несмотря на то, что во время построения было установлено значение не -null).

То, что вы хотите, вероятно, (а), что никто не видит null и (б), что никто не видит частично построенный объект. Чтобы получить это, вам нужно, чтобы класс был свободен от гонок данных. Для этого вам нужны отношения "дожидаться".

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

Итак, что ответ?

JLS немного в этом случае. Там детальное описание инициализации класса в JLS 12.4.2, которое включает в себя блокировку в классе и, таким образом, вводит фронт, предшествующий началу. Но в JLS нет ничего, чтобы указать, что происходит, когда класс уже инициализирован! В этих случаях JLS не требует блокировки и, следовательно, не устанавливает каких-либо связей между ними. Строгое чтение JLS предполагает, что клиенты в других потоках могут видеть null ссылочный или частично построенный объект.

JLS намекает, что этого не должно быть в 12.4.1:

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

Что ж, это здорово, что это "намерение", но там ничего (кроме этого заявления о намерениях) не требуется.

final поле (статическое или нет) получает специальную семантику безопасности потока (JLS 17.5 или см. Этот вопрос на SO), который по существу обеспечивает вышеупомянутый край, предшествующий фронту, и, таким образом, устраняет гонку данных и обеспечивает null ссылку non- на полностью построенный объект.

  • 0
    Вау ... Отличный ответ .. :)
  • 0
    так что то, что вы в основном говорите, final имеет особую семантику безопасности потоков, и вы можете быть уверены с вашей точки зрения.
Показать ещё 1 комментарий
1

В случае кода, который вы указали, нет никакой разницы, потому что у вас нет метода фактического установки нового экземпляра класса Singleton потому что у вас нет каких-либо конструкторов или сеттеров, видимых вне класса.

Однако это не означает, что без final можно было бы изменить экземпляр Singleton. API Reflection можно теоретически использовать для изменения экземпляра, если у вас не было final квалификатора. Я говорю теоретически, потому что я никогда не пробовал это сам, и я не могу придумать путь от головы. Я уступаю любому, у кого есть немного больше опыта с API Reflection

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню