github源码地址
func newCacheWithJanitor(de time.Duration, ci time.Duration, m map[string]*Item) *Cache { c := newCache(de, m) // This trick ensures that the janitor goroutine (which--granted it // was enabled--is running DeleteExpired on c forever) does not keep // the returned C object from being garbage collected. When it is // garbage collected, the finalizer stops the janitor goroutine, after // which c can be collected. C := &Cache{c} if ci > 0 { runJanitor(c, ci) runtime.SetFinalizer(C, stopJanitor) } return C}这段程序的关键点在于C := &Cache{c} 和* runtime.SetFinalizer(C, stopJanitor)*
首先,
func (j *janitor) Run(c *cache) { j.stop = make(chan bool) tick := time.Tick(j.Interval) for { select { case <-tick: c.DeleteExpired() case <-j.stop: return } }}func runJanitor(c *cache, ci time.Duration) { j := &janitor{ Interval: ci, } c.janitor = j go j.Run(c)}可以看到runJanitor是启动了一个goroutine用于清除过期的缓存,这个goroutine是一直执行的,周期的检查c中有没有过期的缓存,所以c一直不会被垃圾回收。为了让程序停掉的时候该gorountine也能够停止,就需要利用C := &Cache{c}和runtime.SetFinalizer.
利用C := &Cache{c}, c虽然不会被垃圾回收,但是C会,那么当C被垃圾回收时,C变成unreachable 的状态,就会触发runtime.SetFinalizer,执行stopJanitor停止runJanitor启动的goroutine。
新闻热点
疑难解答