TGViewer
Евгений Козлов пишет про IT Евгений Козлов пишет про IT @careerunderhood · 2.83K subscribers
Post #451 2.04K
Concurrency, Synchronization and Consistency. Double checked locking problem

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

Представьте что у нас конкурентное приложение. И в нем есть объект обязанный существовать в единственном экземпляре. С ним и будут работать наши потоки. Инициализация объекта тяжелая, занимает какое то время.

Варианты:
- Инициализация ресурса на старте.
- Инициализация в момент запроса ресурса (lazy init).

Вы с командой подумали и решили - на старте слишком долго, давайте делать лениво. Посидели, подумали и получилось вот так:
type Cache struct {
data map[string]string
}

type Service struct {
cache *Cache
mu sync.Mutex
}

func (s *Service) GetCache() *Cache {
s.mu.Lock()
defer s.mu.Unlock()

if s.cache == nil {
s.cache = &Cache{
data: make(map[string]string),
}
}
return s.cache
}

Всё четко работает, но после релиза видите по метрикам и профилировщику что горутины начали конкурировать в этом кусочке кода (он вызывается часто). Надо что-то менять, и вы приходите к выводу - мьютекс нужен только когда объект не существует, иначе нужно просто вернуть ресурс.
package main

// код выше не изменился

func (s *Service) GetCache() *Cache {
if s.cache == nil {
s.mu.Lock()
defer s.mu.Unlock()

if s.cache == nil {
s.cache = &Cache{
data: make(map[string]string),
}
}
}
return s.cache
}

Все работает четко, но код слегка попахивает. Можно ли красивее?
// код выше не изменился

type Service struct {
cache *Cache
once sync.Once
}

func (s *Service) GetCache() *Cache {
s.once.Do(func() {
s.cache = &Cache{
data: make(map[string]string),
}
})
return s.cache
}

Это и есть Double Checked Locking (DCL). На первый взгляд может показаться что проблема высосана из пальца, но на самом деле Go просто обошелся малой кровью - спасибо за простую модель памяти. В Java раньше был целый челлендж с тем чтобы правильно написать подобный код - почитать об этом можно здесь и здесь. Вторая ссылка так вообще монументальная, под ней подписался в том числе Joshua Bloch - автор Effective Java. В его книге как раз есть глава посвященная этой проблеме. Если на моем канале есть джависты, ставьте 🐳 и рассказывайте как вы писали свой первый синглтон😁

Приходилось ли вам писать подобный код и к чему это привело?
Problem pioneer “Double-checked locking is a matter of style, not performance” Double-checked locking is 100 times faster than synchronized locking, but there’s a caveat
  • 🔥 8
  • 🐳 7
  • ❤ 5
  • 👍 1
More from @careerunderhood
  1. Sep 30, 2026Результаты опроса меня впечатлили. Большинству интересны истории из работы. Поехали, начне…
  2. Sep 25, 2026Post #470
  3. Sep 21, 2026Concurrency, Synchronization and Consistency. Non-blocking. Оглавление Введение - Блокирую…
  4. Sep 21, 2026Concurrency and Consistency. Non-blocking, lock-free and async. Пост №12. Заключение. Когд…
  5. Sep 20, 2026Concurrency and Consistency. Non-blocking, lock-free and async. Пост №11. Самые важные фак…
  6. Sep 19, 2026Concurrency and Consistency. Non-blocking, lock-free and async. Пост №10. Продвинутые wait…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →