Ответ
Потокобезопасный синглтон гарантирует, что только один экземпляр класса будет создан в многопоточной среде.
Способы реализации в Kotlin:
object(ленивая инициализация, потокобезопасно по умолчанию):
object Singleton
- Double-Checked Locking (оптимизирован для Java/Kotlin):
class Singleton private constructor() {
companion object {
@Volatile private var instance: Singleton? = null
fun getInstance(): Singleton = instance ?: synchronized(this) {
instance ?: Singleton().also { instance = it }
}
}
}
Ключевые моменты:
@Volatileпредотвращает кэширование переменной в потоках.synchronizedблокирует создание экземпляра в многопоточной среде.- Ленивая инициализация (
by lazy) в Kotlin тоже потокобезопасна по умолчанию.
Ответ 18+ 🔞
А, ну это классика, ёпта! Ты знаешь, как иногда бывает — нужна тебе одна штука на весь проект, одна-единственная, а её на всех не хватает. Вот представь: у тебя есть последняя печенька в офисе, и если её не охранять, то какой-нибудь хитрожопый коллега её сожрёт, пока ты кофе наливаешь. Так и с синглтоном — нужно сделать так, чтобы эта «печенька» была одна, и чтобы даже если двадцать потоков одновременно на неё набросятся, они не поругались и не создали двадцать одинаковых печенек. Это пиздец как важно, когда ресурс общий.
Вот, смотри, в Котлине есть способ, от которого просто терпения ноль ебать — настолько он простой. Просто пишешь object Singleton, и всё, приехали. Компилятор сам под капотом делает всё, чтобы эта штука создалась один раз и была безопасной для потоков. Это как волшебство, ни хуя себе!
object Singleton
Вот и весь разговор. Но если тебе, чувак, интересно, как это раньше, в старые добрые времена, делали вручную (или если ты из тех, кто любит поковыряться в грязи), то есть паттерн «Double-Checked Locking». Выглядит он, конечно, пиздопроебибна, но логика в нём есть.
class Singleton private constructor() {
companion object {
@Volatile private var instance: Singleton? = null
fun getInstance(): Singleton = instance ?: synchronized(this) {
instance ?: Singleton().also { instance = it }
}
}
}
Давай разберём эту манду с ушами:
@Volatile— это такая примочка для переменной. Она кричит всем потокам: «Эй, мудаки, не кэшируйте меня у себя в ядре, читайте самое свежее значение из оперативки!» Без этого один поток мог бы создать экземпляр, а другой его даже не увидеть — доверия ебать ноль к таким ситуациям.synchronized(this)— это наш вышибала, охранник у входа. Он говорит: «Ребята, создавать экземпляр будет только один из вас, остальные — постойте тут, побздите немного». Он блокирует кусок кода, чтобы туда не вломилась толпа.- А дальше идёт проверка внутри блока: «А может, пока я стоял в очереди, какой-то пидарас шерстяной уже всё создал?» Если да — возвращаем его экземпляр. Если нет — создаём свой и запоминаем.
Ключевые моменты, чтобы не облажаться:
- Этот
@Volatile— не просто так, он реально нужен, иначе будет хиросима и нигерсраки в многопоточке. - В Котлине, если честно, проще всего использовать
by lazyдля свойств — эта штука тоже по умолчанию потокобезопасная. То есть можно не городить этот ёперный театр с блокировками, а довериться языку. Но знать, как оно работает под капотом — это всегда полезно, а то подозрение ебать чувствую, что однажды это вылезет на собеседовании.
Короче, суть в том, чтобы твой единственный экземпляр не превратился в овердохуища копий из-за жадных потоков. Выбирай способ по ситуации, но object — это обычно пизда рулю.