package main; import ( "sync" "errors" "fmt" ) //代码参考《Go语言实战》中第7章并发模式Pool //如果哪个类型实现了Resource接口中的两个方法,我们就认为该类型是资源 type Resource interface { Close(); IsClosed() bool; } //工厂方法,用于创建新资源 type Factory func() (Resource, error) //资源池 type ResourcePool struct { //互斥锁,保证池中资源的安全 mu sync.Mutex; //通道,用于保存资源 res chan Resource; //工厂方法 factory Factory; //判断资源池是否关闭 closed bool; } //创建一个资源池 func NewResourcePool(factory Factory, cap int) (*ResourcePool, error) { if cap > 0 { return &ResourcePool{ mu: sync.Mutex{}, res: make(chan Resource, cap), factory: factory, closed: false, }, nil; } return nil, errors.New("cap应大于0"); } //从资源池中获取一个资源 func (rp *ResourcePool) Get() (Resource, error) { if rp.closed { return nil, errors.New("资源池已关闭"); } select { //获取资源,判断通道是否关闭 case item, ok := <-rp.res: { if !ok { return nil, errors.New("资源池已关闭"); } return item, nil; } default: { //返回工厂创建的资源 return rp.factory(); } } } //将资源放入池中 func (rp *ResourcePool) Put(res Resource) error { if rp.closed { return errors.New("资源池已关闭"); } select { //当res无法插入时,这里会阻塞,select执行default case rp.res <- res: { return nil; } default: { res.Close(); return errors.New("资源池已满"); } } } //关闭资源池 func (rp *ResourcePool) Close() { if rp.closed { return; } rp.mu.Lock(); //关闭资源池 rp.closed = true; //关闭通道,不在往通道中添加新资源 close(rp.res); //循环关闭通道中的资源 for item := range rp.res { if !item.IsClosed() { item.Close(); } } rp.mu.Unlock(); } //自定义一个资源类型 type Data struct { data []byte; } func (d Data) Close() { d.data = nil; } func (d Data) IsClosed() bool { if len(d.data) > 0 { return true; } else { return false; } } func (d Data) Write(b []byte) { copy(d.data, b); } func main() { //创建一个资源池 pool, _ := NewResourcePool(func() (Resource, error) { return Data{ data: make([]byte, 16), }, nil; }, 3); //获取资源 item1, _ := pool.Get(); item1.(Data).Write([]byte("123")); item2, _ := pool.Get(); item2.(Data).Write([]byte("456")); item3, _ := pool.Get(); item3.(Data).Write([]byte("789")); fmt.Println(item1); fmt.Println(item2); fmt.Println(item3); //我们再获取一个资源 item4, _ := pool.Get(); //我们把源资入回池中 pool.Put(item1); pool.Put(item2); pool.Put(item3); //这里就会报错了,因为我们创建池时,设置的大小为3 err := pool.Put(item4); if err != nil { fmt.Println(err); } //关闭资源池 pool.Close(); }