Fundamentals 5 min read

Understanding the Singleton Pattern in Go: Eager vs Lazy Implementations

The article explains Go's singleton pattern, detailing eager (init) and lazy implementations using sync.Mutex and sync.Once, provides full code examples, demonstrates that each accessor returns the same instance, and discusses trade‑offs between memory usage and performance.

Nullbody Notes
Nullbody Notes
Nullbody Notes
Understanding the Singleton Pattern in Go: Eager vs Lazy Implementations

Singleton Pattern in Go

The singleton pattern restricts a class to a single instance by making the constructor private and exposing a static public accessor. In Go this is expressed by defining a private struct type and providing package‑level functions that return the sole instance.

Three concrete implementations

Eager (init) implementation – the instance is created in an init function, which runs automatically when the package is imported.

Lazy implementation with sync.Mutex – the instance is created on the first call; a mutex protects the double‑checked locking sequence.

Lazy implementation with sync.Once – the instance is created exactly once by calling once.Do.

Code

package singleton

import "sync"

// ----- Lazy implementation (Mutex) -----
var mu sync.Mutex

type lazy struct {
    Name string
}

var l *lazy = nil

func GetLazy() *lazy {
    if l == nil {
        mu.Lock()
        if l == nil {
            l = new(lazy)
            l.Name = "Lazy man"
        }
        mu.Unlock()
    }
    return l
}

// ----- Lazy implementation (Once) -----
var once sync.Once

type lazyonce struct {
    Name string
}

var lo *lazyonce = nil

func GetOnce() *lazyonce {
    once.Do(func() {
        lo = &lazyonce{Name: "lazyOnce"}
    })
    return lo
}

// ----- Eager implementation (init) -----
var h *hungry = nil

type hungry struct {
    Name string
}

func init() {
    h = new(hungry)
    h.Name = "Hungry man"
}

func GetHungry() *hungry {
    return h
}

Usage demonstration

func main() {
    fmt.Println("单例模式")

    h1 := singleton.GetHungry()
    h2 := singleton.GetHungry()
    if h1 == h2 {
        fmt.Println("h1==h2")
    }

    l1 := singleton.GetLazy()
    l2 := singleton.GetLazy()
    if l1 == l2 {
        fmt.Println("l1==l2")
    }

    lo1 := singleton.GetOnce()
    lo2 := singleton.GetOnce()
    if lo1 == lo2 {
        fmt.Println("lo1==lo2")
    }
}

Running the program prints:

单例模式
h1==h2
l1==l2
lo1==lo2

Key points of each getter

GetLazy() – uses a sync.Mutex to ensure the global variable l is assigned only once.

GetOnce() – relies on sync.Once 's Do method, which guarantees the initialization function runs exactly once, assigning lo a single value.

GetHungry() – returns the instance created by the package‑level init function, which executes before any caller code.

Comparison of lazy vs eager approaches

Lazy (Mutex / Once) – the object is allocated only when the accessor is first invoked, saving memory for rarely used singletons.

Eager (init) – the object is allocated during package import, eliminating synchronization overhead at call time and favoring speed over memory consumption.

The choice between these implementations depends on project requirements: memory‑constrained scenarios may prefer lazy initialization, while performance‑critical code may opt for eager initialization.

Source repository: https://github.com/gofish2020/gopattern/tree/main/creator

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

concurrencyGoDesign PatternSingletonsync.Onceinitsync.Mutex
Nullbody Notes
Written by

Nullbody Notes

Go backend development, learning open-source project source code together, focusing on simplicity and practicality.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.