Go Concurrency

Go sync.Mutex

Stop goroutines from losing updates when they change the same value.

  • Advanced
  • 4 min read
  • 1 runnable example
What you'll learn
  • Lock and Unlock
  • defer Unlock
  • Why the count is always right
4 goroutines x 1000 increments
  1. 1mu.Lock()one at a time
  2. 2count++safe update
  3. 3mu.Unlock()next goroutine
  4. 44000always

One goroutine at a time

When goroutines change the same variable at the same time, updates can be lost. A Mutex is a lock: only the goroutine that holds it may touch the data.

Lock waits until no other goroutine holds the lock, and defer Unlock releases it when the method returns. Without the mutex, count++ from four goroutines would lose updates. Four goroutines each add 1000, so the result is always 4000.

Key points

  1. Lock waits until the mutex is free.
  2. defer Unlock releases it on return.
  3. Without a lock, count++ can lose updates.

Runnable Go example

Go
Run code →
main.go
package main

import (
	"fmt"
	"sync"
)

type Counter struct {
	mu    sync.Mutex
	count int
}

func (c *Counter) Increment() {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.count++
}

func (c *Counter) Value() int {
	c.mu.Lock()
	defer c.mu.Unlock()
	return c.count
}

func main() {
	counter := &Counter{}
	var wg sync.WaitGroup

	for i := 0; i < 4; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			for j := 0; j < 1000; j++ {
				counter.Increment()
			}
		}()
	}

	wg.Wait()
	fmt.Println("final count:", counter.Value())
}
Get a Run button for this example Result of running the code
final count: 4000

Practice

Open the example in the online compiler, change a value or add a line, and predict the output before you run it. Then break the code on purpose and read the compiler's message.

Finished this lesson?

Mark it as learned to track your progress.

Next: Worker Pool →

Practice with a challenge

Use what this lesson covers to solve a real problem. Each challenge runs in your browser with instant tests and an AI review.

All challenges