Golang中的锁机制主要包括两类:互斥锁(sync.Mutex)和读写锁(sync.RWMutex)。互斥锁用于保护共享资源的独占访问,而读写锁则允许多个读操作同时进行,但只允许一个写操作。

下面是一个互斥锁的使用示例:

package main

import (
    "fmt"
    "sync"
)

var (
    counter int
    mutex sync.Mutex
    wg sync.WaitGroup
)

func main() {
    // 启动10个goroutine去增加计数器
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go increment()
    }

    // 等待所有goroutine完成
    wg.Wait()

    fmt.Println("Final counter:", counter)
}

func increment() {
    defer wg.Done()

    // 对共享资源加锁
    mutex.Lock()
    defer mutex.Unlock()

    // 对计数器加1
    counter++
    fmt.Println("Counter:", counter)
}

这个示例中,我们定义了一个全局的计数器和一个互斥锁。然后启动10个goroutine,每个goroutine都会尝试对计数器进行加1操作。但由于对计数器的访问是独占的,我们需要在对计数器进行修改之前对其加锁,以防止其他goroutine同时访问导致数据出错。

在 `increment` 函数中,我们使用 `mutex.Lock()` 和 `mutex.Unlock()` 将对共享资源的操作加锁和解锁。注意,在加锁之后,我们使用了 defer 语句来确保在函数结束时自动解锁,以防止程序在执行期间由于某种原因而无法解锁,从而导致死锁。

在主函数中,我们启动了10个goroutine,并等待它们都完成后再输出计数器的最终值。这里使用了 `sync.WaitGroup` 来实现等待所有goroutine完成的功能。

下面是一个读写锁的使用示例:

package main

import (
    "fmt"
    "sync"
    "time"
)

var (
    value int
    rwMutex sync.RWMutex
    wg sync.WaitGroup
)

func main() {
    wg.Add(3)

    // 启动3个goroutine进行读操作
    for i := 0; i < 3; i++ {
        go read(i+1)
    }

    // 启动一个goroutine进行写操作
    go write(4)

    wg.Wait()
}

func read(id int) {
    defer wg.Done()

    // 对读锁进行操作
    rwMutex.RLock()
    defer rwMutex.RUnlock()

    fmt.Printf("Reader %d: %d\n", id, value)
    time.Sleep(time.Second)
}

func write(id int) {
    defer wg.Done()

    // 对写锁进行操作
    rwMutex.Lock()
    defer rwMutex.Unlock()

    value = 100
    fmt.Printf("Writer %d: set value to %d\n", id, value)
    time.Sleep(time.Second)
}

在这个示例中,我们定义了一个全局变量 `value` 和一个读写锁 `rwMutex`,并且启动了3个goroutine进行读操作和一个goroutine进行写操作。

在读操作中,我们用 `rwMutex.RLock()` 和 `rwMutex.RUnlock()` 对读锁进行加锁和解锁。由于我们使用的是读锁,因此多个goroutine可以同时读取该变量的值,而不会互相干扰。

在写操作中,我们用 `rwMutex.Lock()` 和 `rwMutex.Unlock()` 对写锁进行加锁和解锁。由于我们使用的是写锁,因此在写操作进行时,其他goroutine不能对该变量进行读或写操作。

在主函数中,我们启动了3个goroutine进行读操作和一个goroutine进行写操作。注意,在这里我们使用的是 `sync.WaitGroup` 保证所有goroutine都执行完毕后程序才结束。