#java #многопоточность #потоки_данных
Например тут: public class Singleton{ private static Cat cat = new Cat(); public static Cat getInstance(){ return cat; } } Почему такой вариант хуже (если хуже), чем использование не статического метода getInstance()? P.S. Цель вопроса выяснить, есть ли разница между использованием статического метода getInstance() и не статического, в ситуации когда к нему могут обращаться много потоков одновременно.
Ответы
Ответ 1
Приведённый вариант лучше, чем вариант с нестатическим getInstance потому, что иначе никак. Если метод нестатический, то придётся создавать класс Singleton каждый раз. Кроме того, очевидно, что вы неправильно реализовали синглтон. Получается, что вы можете получать экземпляр класса Cat через Singleton, а можете просто создавать через new Cat сколько угодно, что будет неверно и вы никак не сможете от этого защититься. Поэтому надо делать public class Cat { private static final Cat cat = new Cat(); public static Cat getInstance(){ return cat; } } С точки зрения многопоточности нет разницы между статическим и нестатическим методом, если он не помечен как synchronized. Приведённый выше вариант, как уже говорилось, имеет недостаток: создание экземпляра при подгрузке класса (часто при старте приложения). Чтобы избежать этой проблемы, можно использовать паттерн Initialization on Demand Holder idiom. public class Cat{ private Cat() { } private static class LazyHolder { private static final Cat INSTANCE = new Cat(); } public static final Cat getInstance() { return LazyHolder.INSTANCE; } } При таком раскладе достигается эффективная потокобезопасность и получена ленивая инициализация (lazy-load singleton). Однако, в большинстве случаев нет необходимости делать такую сложную конструкцию, а достаточно реализовать первым способом.Ответ 2
Я смотрю тут дискуссия свелась к обсуждению паттерна singleton :) Собственно, если отвечать на вопрос "Как ведет себя static метод в многопоточном приложении?" нужно знать следующее: 1) Из static метода доступны только static поля и методы, поэтому проблемы могут возникнуть только с ними (или еще с передаваемыми в метод параметрами и объектами, сохраненными в локальных переменных, но это уже не зависит от использования static), а если точнее - при записи в static поля. В приведенном примере запись в такое поле производится лишь однажды - при загрузке класса. 2) Использование synchronized static метода абсолютно равносильно использованию объекта класса как мьютекса. Следующие два метода работают идентично: class Example{ static void foo(){ synchronized(Example.class){ //method body } } synchronized static void bar(){ //method body } } 3) Без использования synchronized в методе или с методом вызов его кода никак не отличается в плане многопоточности от вызова обыкновенного метода. Напоследок предложу еще один способ реализации паттерна singleton, на мой взгляд весьма изящный и эффективный - никаких проблем с инициализацией/многопоточностью enum Singleton{ Instance; //methods }Ответ 3
Метод getInstance в реализации паттерна Singleton может быть только статическим. Потому что это основная идея паттерна: объект должен быть только один и должен быть доступен из любого класса нашего приложения. В такой реализации паттерна не возникнет никаких проблем с многопоточностью, потому что операция модификации здесь только new Cat(), которая будет вызвана только один раз. Другой вопрос, что такая реализация паттерна хороша только если Вы абсолютно уверены, что в конструкторе не может быть исключения Вам неважно то, что инициализация происходит при запуске приложения, а не в момент первого обращения Действительно, многие синглтоны имеют пустой или простой и быстроисполняемый конструктор. Тогда эти два пункта можно не учитывать. Но иногда разработчик всё-таки заинтересован в ленивой загрузке и проверке на исключения. Проблемы возникают тогда, когда метод getInstance выглядит так: public static Cat getInstance(){ if (cat == null) cat = new Cat(); return cat; } Здесь действительно будут проблемы с многопоточностью. Поэтому для любых неатомарных операций стоит использовать модификатор synchronized. Иначе мы не сможем гарантировать, что объект Cat создаться лишь один раз. Если есть желание хорошо разобраться с многопоточностью в Java, советую прочитать Java Concurrency и мануал на сайте Oracle.
Комментариев нет:
Отправить комментарий