工作中碰到缓存失败时,数据库的惊群,本来之前用Redis的SETNX来做锁处理,后来想想,既然用golang写了服务,当然可以把锁直接做在内存里,就自己写了一小段代码。
package resourceslock import ( "errors" "sync" ) var ( Lock resourcesLock = resourcesLock{ lockerMapMtx: new(sync.Mutex),lockerMap: make(map[ResourceTopic]chan void),topicWaitlistMtx: make(map[ResourceTopic]*sync.Mutex),topicWaitlist: make(map[ResourceTopic][]chan bool),} // universal lock voidMsg void = void{} ) type ResourceTopic string type ProtectCondition func() bool type ReloadFunc func() (interface{},error) type void struct{} type resourcesLock struct { lockerMapMtx *sync.Mutex topicWaitlistMtx map[ResourceTopic]*sync.Mutex lockerMap map[ResourceTopic](chan void) topicWaitlist map[ResourceTopic][](chan bool) } func (self *resourcesLock) Protect(topic ResourceTopic,cond *ProtectCondition,reload *ReloadFunc) error { if (*cond)() == true { return nil } var err error self.createLockChn(topic) select { case <-self.lockerMap[topic]: _,err = (*reload)() if err != nil { self.notifyError(topic) } else { self.notifySuccess(topic) } self.lockerMap[topic] <- voidMsg default: if !<-self.addToWaitlist(topic) { err = errors.New("Resource is not refreshed.") } } return err } func (self *resourcesLock) createLockChn(topic ResourceTopic) { self.lockerMapMtx.Lock() _,ok := self.lockerMap[topic] if !ok { ch := make(chan void,1) ch <- voidMsg self.lockerMap[topic] = ch self.topicWaitlistMtx[topic] = new(sync.Mutex) } self.lockerMapMtx.Unlock() } func (self *resourcesLock) addToWaitlist(topic ResourceTopic) <-chan bool { ch := make(chan bool) self.topicWaitlistMtx[topic].Lock() self.topicWaitlist[topic] = append(self.topicWaitlist[topic],ch) self.topicWaitlistMtx[topic].Unlock() return ch } func (self *resourcesLock) notifyError(topic ResourceTopic) { self.notify(topic,false) } func (self *resourcesLock) notifySuccess(topic ResourceTopic) { self.notify(topic,true) } func (self *resourcesLock) notify(topic ResourceTopic,suc bool) { self.topicWaitlistMtx[topic].Lock() for i,c := range self.topicWaitlist[topic] { if suc { c <- true } else { c <- false } self.topicWaitlist[topic][i] = nil } self.topicWaitlist[topic] = self.topicWaitlist[topic][:0] self.topicWaitlistMtx[topic].Unlock() }原文链接:https://www.f2er.com/go/189320.html