必须填写至少10个字的日志
nnhy 编写于 2012-07-27 18:48:21
X
using System;
using System.Diagnostics;
using System.Threading;
using NewLife.Log;
using NewLife.Reflection;
using NewLife.Threading;

namespace NewLife.Collections
{
    /// <summary>对象池。采用原子栈设计,避免锁资源的争夺。</summary>
    /// <remarks>
    /// 经过测试,对象数量在万级以上时,性能下降很快!
    /// </remarks>
    /// <typeparam name="T"></typeparam>
    public class ObjectPool<T> : DisposeBase //where T : new()
    {
        #region 属性
        private IStack<T> _Stock;
        /// <summary>在库</summary>
        public IStack<T> Stock { get { return _Stock; } set { _Stock = value; } }

        private Int32 _Max = 1000;
        /// <summary>最大缓存数。默认1000,超过后将启用定时器来清理</summary>
        public Int32 Max { get { return _Max; } set { _Max = value; } }

        /// <summary>在库</summary>
        public Int32 StockCount { get { return _Stock.Count; } }

        /// <summary>不在库</summary>
        public Int32 NotStockCount { get { return CreateCount - StockCount - FreeCount; } }

        private Int32 _FreeCount;
        /// <summary>被释放的对象数</summary>
        public Int32 FreeCount { get { return _FreeCount; } set { _FreeCount = value; } }

        private Int32 _CreateCount;
        /// <summary>创建数</summary>
        public Int32 CreateCount { get { return _CreateCount; } }
        #endregion

        #region 构造
        /// <summary>实例化一个对象池</summary>
        public ObjectPool() { Stock = new InterlockedStack<T>(); }
        #endregion

        #region 事件
        /// <summary>对象创建委托。在对象池内对象不足时调用,如未设置,则调用类型的默认构造函数创建对象。</summary>
        public Func<T> OnCreate;
        #endregion

        #region 方法
        /// <summary>归还</summary>
        /// <param name="obj"></param>
        public virtual void Push(T obj)
        {
            // 释放后,不再接受归还,因为可能别的线程尝试归还
            if (Disposed) return;

            var stack = Stock;

            // 超过最大值了,启动清理定时器
            if (stack.Count > Max)
            {
                if (_clearTimers == null) _clearTimers = new TimerX(ClearAboveMax, null, 0, XTrace.Debug ? 10000 : 120000);
            }
            else
            {
                // 没到最大值,关闭定时器?
                if (stack.Count < Max - 100 && _clearTimers != null)
                {
                    _clearTimers.Dispose();
                    _clearTimers = null;
                }
            }

            stack.Push(obj);
        }

        /// <summary>借出</summary>
        /// <returns></returns>
        public virtual T Pop()
        {
            var stack = Stock;

            T obj;
            if (stack.TryPop(out obj))
            {
                Debug.Assert(obj != null);
                return obj;
            }

            obj = Create();
            Interlocked.Increment(ref _CreateCount);

            return obj;
        }

        /// <summary>创建实例</summary>
        /// <returns></returns>
        protected virtual T Create()
        {
            if (OnCreate != null) return OnCreate();

            return (T)TypeX.CreateInstance(typeof(T));
        }
        #endregion

        #region 清理定时器
        TimerX _clearTimers;

        void ClearAboveMax(Object state)
        {
            var stack = Stock;

            // 把超标的全部清了
            while (stack.Count > Max)
            {
                IDisposable obj = stack.Pop() as IDisposable;
                if (obj != null) obj.Dispose();

                Interlocked.Increment(ref _FreeCount);
            }

            // 没到最大值,关闭定时器?
            if (stack.Count < Max - 100 && _clearTimers != null)
            {
                _clearTimers.Dispose();
                _clearTimers = null;
            }
        }
        #endregion

        #region 释放资源
        /// <summary>子类重载实现资源释放逻辑</summary>
        /// <param name="disposing">从Dispose调用(释放所有资源)还是析构函数调用(释放非托管资源)</param>
        protected override void OnDispose(Boolean disposing)
        {
            base.OnDispose(disposing);

            if (disposing)
            {
                // 释放托管资源
                if (_Stock != null)
                {
                    _Stock.Dispose();
                    _Stock = null;
                }
            }

            if (_clearTimers != null)
            {
                _clearTimers.Dispose();
                _clearTimers = null;
            }
        }
        #endregion
    }
}