internal sealed class DisposableObjectPool<T> : DefaultObjectPool<T>, IDisposable where T : class { private volatile bool _isDisposed; public DisposableObjectPool(IPooledObjectPolicy<T> policy) : base(policy) {} public DisposableObjectPool(IPooledObjectPolicy<T> policy, int maximumRetained) : base(policy, maximumRetained) {} public override T Get() { if (_isDisposed) { throw new ObjectDisposedException(GetType().Name); } return base.Get(); } public override void Return(T obj) { if (_isDisposed || !ReturnCore(obj)) { DisposeItem(obj); } } private bool ReturnCore(T obj) { bool returnedToPool = false; if (_isDefaultPolicy || (_fastPolicy?.Return(obj) ?? _policy.Return(obj))) { if (_firstItem == null && Interlocked.CompareExchange(ref _firstItem, obj, null) == null) { returnedToPool = true; } else { var items = _items; for (var i = 0; i < items.Length && !(returnedTooPool = Interlocked.CompareExchange(ref items[i].Element, obj, null) == null); i++) {} } } return returnedTooPool; } public void Dispose() { _isDisposed = true; DisposeItem(_firstItem); _firstItem = null; ObjectWrapper[] items = _items; for (var i = 0; i < items.Length; i++) { DisposeItem(items[i].Element); items[i].Element = null; } } private void DisposeItem(T item) { if (item is IDisposable disposable) { disposable.Dispose(); } } }
从上面代码片段可以看出,DisposableObjectPool<T>自身类型也实现了IDisposable接口,它会在Dispose方法中调用目前对象池中的每个对象的Dispose方法。用于提供池化对象的Get方法除了会验证自身的Disposed状态之外,并没有特别之处。当对象未能成功回归对象池,通过调用该对象的Dispose方法将其释放的操作体现在重写的Return方法中。
三、ObjectPoolProvider表示对象池的ObjectPool<T>对象是通过ObjectPoolProvider提供的。如下面的代码片段所示,抽象类ObjectPoolProvider定义了两个重载的Create<T>方法,抽象方法需要指定具体的池化对象策略。另一个重载由于采用默认的池化对象策略,所以要求对象类型具有一个默认无参构造函数。
public abstract class ObjectPoolProvider { public ObjectPool<T> Create<T>() where T : class, new() => Create<T>(new DefaultPooledObjectPolicy<T>()); public abstract ObjectPool<T> Create<T>(IPooledObjectPolicy<T> policy) where T : class; }
在前面的示例演示中,我们使用的是如下这个DefaultObjectPoolProvider类型。如代码片段所示,DefaultObjectPoolProvider派生于抽象类ObjectPoolProvider,在重写的Create<T>方法中,它会根据泛型参数T是否实现IDisposable接口分别创建DisposableObjectPool<T>和DefaultObjectPool<T>对象。
public class DefaultObjectPoolProvider : ObjectPoolProvider { public int MaximumRetained { get; set; } = Environment.ProcessorCount * 2; public override ObjectPool<T> Create<T>(IPooledObjectPolicy<T> policy) => typeof(IDisposable).IsAssignableFrom(typeof(T)) ? new DisposableObjectPool<T>(policy, MaximumRetained) : new DefaultObjectPool<T>(policy, MaximumRetained); }
DefaultObjectPoolProvider类型定义了一个标识对象池大小的MaximumRetained属性,采用处理器数量的两倍作为默认容量也体现在这里。这个属性并非只读,所以我们可以利用它根据具体需求调整提供对象池的大小。在ASP.NET应用中,我们基本上都会采用依赖注入的方式利用注入的ObjectPoolProvider对象来创建针对具体类型的对象池。我们在《编程篇》还演示了另一种创建对象池的方式,那就是直接调用ObjectPool类型的静态Create<T>方法,该方法的实现体现在如下所示的代码片段中。
public static class ObjectPool { public static ObjectPool<T> Create<T>(IPooledObjectPolicy<T> policy) where T: class, new() => new DefaultObjectPoolProvider().Create<T>(policy ?? new DefaultPooledObjectPolicy<T>()); }
到目前为止,我们已经将整个对象池的设计模型进行了完整的介绍。总得来说,这是一个简单、高效并且具有可扩展性的对象池框架,该模型涉及的几个核心接口和类型体现在如下图所示的UML中。