面试题答案
一键面试设计思路
- 引入 context:在每个读操作和写操作中引入
context.Context
。context
可以传递取消信号,用于控制读操作的生命周期。 - 写操作广播:当写操作开始时,通过一个广播机制通知所有正在进行或即将开始的读操作。
- 读操作监听:读操作在执行过程中监听
context
的取消信号。一旦收到取消信号,立即停止当前操作,等待或根据具体逻辑取消。
关键代码片段(以 Go 语言为例)
package main
import (
"context"
"fmt"
"sync"
"time"
)
// 模拟缓存数据
type Cache struct {
data map[string]string
rwMutex sync.RWMutex
}
// 写操作
func (c *Cache) Write(ctx context.Context, key, value string) {
c.rwMutex.Lock()
defer c.rwMutex.Unlock()
// 模拟写操作耗时
select {
case <-ctx.Done():
fmt.Println("Write operation cancelled")
return
case <-time.After(2 * time.Second):
c.data[key] = value
fmt.Println("Write operation completed")
}
}
// 读操作
func (c *Cache) Read(ctx context.Context, key string) (string, bool) {
c.rwMutex.RLock()
defer c.rwMutex.RUnlock()
// 模拟读操作耗时
select {
case <-ctx.Done():
fmt.Println("Read operation cancelled")
return "", false
case <-time.After(1 * time.Second):
value, ok := c.data[key]
return value, ok
}
}
func main() {
cache := Cache{data: make(map[string]string)}
// 启动一个写操作
ctx, cancel := context.WithCancel(context.Background())
go func() {
cache.Write(ctx, "key1", "value1")
}()
// 启动多个读操作
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go func() {
defer wg.Done()
value, ok := cache.Read(ctx, "key1")
if ok {
fmt.Printf("Read value: %s\n", value)
}
}()
}
// 模拟写操作开始后,取消读操作
time.Sleep(1 * time.Second)
cancel()
wg.Wait()
}
在上述代码中:
Cache
结构体使用sync.RWMutex
实现读写锁。Write
方法在写操作前加写锁,在操作过程中监听context
的取消信号。Read
方法在读操作前加读锁,同样监听context
的取消信号。- 在
main
函数中,启动一个写操作和多个读操作,通过context
控制读操作在写操作开始后被取消。