从第二个构造函数的定义可以看出,指定的IPooledObjectPolicy<T>对象除了会赋值给_policy字段之外,如果提供的是一个PooledObjectPolicy<T>对象,该对象还会同时赋值给另一个名为_fastPolicy的字段。在进行池化对象的提取和释放时,_fastPolicy字段表示的池化对象策略会优先选用,这个逻辑体现在Create方法上。因为调用类型的方法比调用接口方法具有更好的性能(所以该字段才会命名为_fastPolicy),这是第三个性能优化的细节。这个细节还告诉我们在自定义池化对象策略的时候,最好将PooledObjectPolicy<T>作为基类,而不是直接实现IPooledObjectPolicy<T>接口。
如下所示的是重写的Get和Return方法的定义。用于提供池化对象的Get方法很简单,它会采用原子操作使用Null将_firstItem字段表示的对象“替换”下来,如果该字段不为Null,那么将其作为返回的对象,反之它会遍历数组的每个ObjectWrapper对象,并使用Null将其封装的对象“替换”下来,第一个成功替换下来的对象将作为返回值。如果所有ObjectWrapper对象封装的对象都为Null,意味着所有对象都被“借出”或者尚未创建,此时返回创建的新对象了。
public class DefaultObjectPool<T> : ObjectPool<T> where T : class { public override T Get() { var item = _firstItem; if (item == null || Interlocked.CompareExchange(ref _firstItem, null, item) != item) { var items = _items; for (var i = 0; i < items.Length; i++) { item = items[i].Element; if (item != null && Interlocked.CompareExchange( ref items[i].Element, null, item) == item) { return item; } } item = Create(); } return item; } public override void Return(T obj) { if (_isDefaultPolicy || (_fastPolicy?.Return(obj) ?? _policy.Return(obj))) { if (_firstItem != null || Interlocked.CompareExchange(ref _firstItem, obj, null) != null) { var items = _items; for (var i = 0; i < items.Length && Interlocked.CompareExchange( ref items[i].Element, obj, null) != null; ++i) {} } } } … }
将对象释放会对象池的Return方法也很好理解。首先它需要判断指定的对象能否释放会对象池中,如果使用的是默认的池化对象策略,答案是肯定的,否则只能通过调用IPooledObjectPolicy<T>对象的Return方法来判断。从代码片段可以看出,这里依然会优先选择_fastPolicy字段表示的PooledObjectPolicy<T>对象以获得更好的性能。
在确定指定的对象可以释放回对象之后,如果_firstItem字段为Null,Return方法会采用原子操作使用指定的对象将其“替换”下来。如果该字段不为Null或者原子替换失败,该方法会便利数组的每个ObjectWrapper对象,并采用原子操作将它们封装的空引用替换成指定的对象。整个方法会在某个原子替换操作成功或者整个便利过程结束之后返回。
DefaultObjectPool<T>之所有使用一个数组附加一个单一对象来存储池化对象,是因为针对单一字段的读写比针对数组元素的读写具有更好的性能。从上面给出的代码可以看出,不论是Get还是Return方法,优先选择的都是_firstItem字段。如果池化对象的使用率不高,基本上使用的都会是该字段存储的对象,那么此时的性能是最高的。
DisposableObjectPool<T>通过前面的示例演示我们知道,当池化对象类型实现了IDisposable接口的情况下,如果某个对象在回归对象池的时候,对象池已满,该对象将被丢弃。与此同时,被丢弃对象的Dispose方法将立即被调用。但是这种现象并没有在DefaultObjectPool<T>类型的代码中体现出来,这是为什么呢?实际上DefaultObjectPool<T>还有如下这个名为DisposableObjectPool<T>的派生类。如代码片段可以看出,表示池化对象类型的泛型参数T要求实现IDisposable接口。如果池化对象类型实现了IDisposable接口,通过默认ObjectPoolProvider对象创建的对象池就是一个DisposableObjectPool<T>对象。