MST

星途 面试题库

面试题:Go语言中如何在Map上实现简单的线程安全操作

在Go语言中,原生的Map不是线程安全的。请描述一种简单的方法来实现一个线程安全的Map,并给出示例代码,例如使用`sync.Mutex`。
15.1万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试
  1. 实现思路
    • 可以通过sync.Mutex来实现线程安全的Map。在对Map进行读写操作前,先获取锁,操作完成后释放锁,这样可以避免多个协程同时操作Map导致的数据竞争问题。
  2. 示例代码
package main

import (
    "fmt"
    "sync"
)

// ThreadSafeMap 线程安全的Map结构体
type ThreadSafeMap struct {
    mu sync.Mutex
    data map[string]interface{}
}

// NewThreadSafeMap 创建一个新的线程安全Map
func NewThreadSafeMap() *ThreadSafeMap {
    return &ThreadSafeMap{
        data: make(map[string]interface{}),
    }
}

// Set 设置键值对
func (t *ThreadSafeMap) Set(key string, value interface{}) {
    t.mu.Lock()
    defer t.mu.Unlock()
    t.data[key] = value
}

// Get 获取键对应的值
func (t *ThreadSafeMap) Get(key string) (interface{}, bool) {
    t.mu.Lock()
    defer t.mu.Unlock()
    value, exists := t.data[key]
    return value, exists
}

func main() {
    safeMap := NewThreadSafeMap()
    var wg sync.WaitGroup

    // 模拟多个协程写操作
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func(num int) {
            defer wg.Done()
            key := fmt.Sprintf("key%d", num)
            safeMap.Set(key, num)
        }(i)
    }

    // 等待所有写操作完成
    wg.Wait()

    // 模拟读操作
    for i := 0; i < 10; i++ {
        key := fmt.Sprintf("key%d", i)
        value, exists := safeMap.Get(key)
        if exists {
            fmt.Printf("Key: %s, Value: %v\n", key, value)
        } else {
            fmt.Printf("Key: %s not found\n", key)
        }
    }
}

在上述代码中:

  • ThreadSafeMap结构体包含一个sync.Mutex和一个原生的map
  • NewThreadSafeMap函数用于创建一个新的线程安全Map实例。
  • Set方法用于设置键值对,先获取锁,操作完成后释放锁。
  • Get方法用于获取键对应的值,同样先获取锁,操作完成后释放锁。
  • main函数中,模拟了多个协程进行写操作,然后进行读操作,展示线程安全Map的使用。