Mastering Go’s sync Package: When and How to Use Its Locks

This article explains the different lock types provided by Go's sync package—including Mutex, RWMutex, Cond, WaitGroup, Once, Map, and Pool—detailing their use cases, code examples, and how they help manage concurrency safely and efficiently.

MaGe Linux Operations
MaGe Linux Operations
MaGe Linux Operations
Mastering Go’s sync Package: When and How to Use Its Locks

Go's sync package offers a variety of lock primitives for concurrent programming. Locks protect shared resources, preventing data races and ensuring consistency, but choosing the right lock balances safety and performance.

1. File lock

File locks are OS‑level locks, unrelated to sync. The example shows how to open a file, acquire an exclusive lock with syscall.Flock, read the file, and release the lock.

func main() {
    var f = "/var/logs/app.log"
    file, err := os.OpenFile(f, os.O_RDWR, os.ModeExclusive)
    if err != nil {
        panic(err)
    }
    defer file.Close()

    // call system lock
    err = syscall.Flock(int(file.Fd()), syscall.LOCK_EX|syscall.LOCK_NB)
    if err != nil {
        panic(err)
    }
    defer syscall.Flock(int(file.Fd()), syscall.LOCK_UN)
    // read file content
    all, err := ioutil.ReadAll(file)
    if err != nil {
        panic(err)
    }

    fmt.Printf("%s", all)
    time.Sleep(time.Second * 10) // simulate long operation
}

Attempting to run the program concurrently results in a panic: panic: resource temporarily unavailable.

2. sync.Mutex

A standard mutual exclusion lock. The example demonstrates a data race when two goroutines increment an int without synchronization.

var i int

func main() {
    go add(&i)
    time.Sleep(time.Second * 3)
    println(i)
}

func add(i *int) {
    for j := 0; j < 10000; j++ {
        *i = *i + 1
    }
}

Running the program yields nondeterministic results because of the race. Using the -race flag reveals the conflict.

go run -race main.go
==================
WARNING: DATA RACE
Read at 0x00000056ccb8 by goroutine 7:
  main.add()
    main.go:23 +0x43
Previous write at 0x00000056ccb8 by goroutine 6:
  main.add()
    main.go:23 +0x59
Goroutine 7 (running) created at:
  main.main()
    main.go:14 +0x76
Goroutine 6 (running) created at:
  main.main()
    main.go:13 +0x52
==================
20000
Found 1 data race(s)
exit status 66

Fixing the race by protecting the increment with a mutex:

func add(i *int) {
    for j := 0; j < 10000; j++ {
        s.Lock()
        *i = *i + 1
        s.Unlock()
    }
}

3. sync.RWMutex

An upgraded lock that allows multiple readers but exclusive writers. Its API includes Lock, Unlock, RLock, RUnlock, and RLocker.

func (rw *RWMutex) Lock()
func (rw *RWMutex) RLock()
func (rw *RWMutex) RLocker() Locker
func (rw *RWMutex) RUnlock()
func (rw *RWMutex) Unlock()

4. sync.Map

A concurrent map that embeds its own lock, avoiding the need for an external mutex.

type User struct {
    m map[string]string
    l sync.Mutex
}

var m sync.Map

func main() {
    m.Store("1", 1)
    m.Store("2", 1)
    m.Store("3", 1)
    m.Store(4, "5") // note type

    load, ok := m.Load("1")
    if ok {
        fmt.Printf("%v
", load)
    }

    load, ok = m.Load(4)
    if ok {
        fmt.Printf("%v
", load)
    }
}

Keys and values are of type interface{}, so type assertions are required when retrieving data.

5. sync.Once

Ensures a function runs only once, useful for lazy initialization or singleton patterns.

package main

import "sync"

var once sync.Once

func main() {
    doOnce()
}

func doOnce() {
    once.Do(func() {
        println("one")
    })
}

6. sync.Cond

A condition variable that blocks goroutines until a specific condition is signaled.

package main
import (
    "sync"
    "time"
)

var cond = sync.NewCond(&sync.Mutex{})

func main() {
    for i := 0; i < 10; i++ {
        go func(i int) {
            cond.L.Lock()
            cond.Wait() // wait for signal
            println(i)
            cond.L.Unlock()
        }(i)
    }
    time.Sleep(time.Second * 1) // ensure all goroutines start
    cond.Signal()
    time.Sleep(time.Second * 1) // give output time
}

Replacing Signal with Broadcast wakes all waiting goroutines.

7. sync.WaitGroup

Coordinates the completion of a set of goroutines.

package main

import "sync"

var wg sync.WaitGroup

func main() {
    for i := 0; i < 10; i++ {
        wg.Add(1) // increment counter
        go func() {
            println("1")
            wg.Done() // decrement counter
        }()
    }
    wg.Wait() // block until counter is zero
}

8. sync.Pool

A pool for temporary objects to reduce allocations. Objects may be reclaimed by GC at any time.

package main

import (
    "fmt"
    "sync"
)

type User struct {
    name string
}

var pool = sync.Pool{
    New: func() interface{} {
        return User{name: "default name"}
    },
}

func main() {
    pool.Put(User{name: "name1"})
    pool.Put(User{name: "name2"})

    fmt.Printf("%v
", pool.Get()) // {name1}
    fmt.Printf("%v
", pool.Get()) // {name2}
    fmt.Printf("%v
", pool.Get()) // {default name} – pool empty, New is called
}

Because sync.Pool is goroutine‑safe, frameworks like Gin use it to cache per‑request contexts.

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.

concurrencymutexRWMutexsyncWaitGroupPool
MaGe Linux Operations
Written by

MaGe Linux Operations

Founded in 2009, MaGe Education is a top Chinese high‑end IT training brand. Its graduates earn 12K+ RMB salaries, and the school has trained tens of thousands of students. It offers high‑pay courses in Linux cloud operations, Python full‑stack, automation, data analysis, AI, and Go high‑concurrency architecture. Thanks to quality courses and a solid reputation, it has talent partnerships with numerous internet firms.

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.