查看Queue的源码发现其实队列里面维护的是一个数组,而且这个数组是一直增加的,队列push一个就放到数组的最后,pop的时候就把数组最前面取出然后置为Null,这样必然导致在大量的pop和push操作后
会在数组前面产生大量的值为Null的数组元素。这个时候就可以用到 TrimToSize 方法进行从新分配数组,把多余的Null去掉。
现在可以实现一个定长的环形堆栈RingStack,可以对循环利用。
/// <summary>
/// 环形堆栈类,长度固定,顶与底相接形成一个圆环,需自定义覆盖时丢弃对象的处理方法
/// </summary>
/// <typeparam name="T">环形堆栈中对象的类型</typeparam>
/// <remarks>属于一个固定大小的堆栈式缓存,当增长速度过快时自动覆盖最先压入的对象</remarks>
public sealed class RingStack<T>
{
/// <summary>
/// 堆栈的容量
/// </summary>
public readonly int Capacity;
/// <summary>
/// 堆栈的数据集
/// </summary>
private T[] _Items;
/// <summary>
/// 堆栈顶部的指针
/// </summary>
private int _TopIndex;
/// <summary>
/// 堆栈底部的指针
/// </summary>
private int _BottomIndex;
/// <summary>
/// 对象的数量
/// </summary>
private int _Count;
/// <summary>
/// 获取堆栈中对象的数量
/// </summary>
/// <remarks>此属性的读取是内部锁定的,因此多线程操作是安全的</remarks>
public int Count
{
get
{
lock (this)
{
return _Count;
}
}
}
/// <summary>
/// 覆盖时丢弃对象的处理方法
/// </summary>
public Action<T> Drop;
/// <summary>
/// 初始化环形堆栈的新实例
/// </summary>
/// <param name="capacity">堆栈的容量</param>
public RingStack(int capacity)
{
Capacity = capacity;
_Items = new T[Capacity];
_TopIndex = _BottomIndex = 0;
_Count = 0;
}
/// <summary>
/// 从堆栈中弹出一个对象
/// </summary>
/// <param name="item">弹出的对象</param>
/// <returns>返回是否成功弹出对象,true表示弹出对象成功,false表示弹出对象失败</returns>
/// <remarks>此操作是内部锁定的,因此多线程操作是安全的</remarks>
public bool Pop(ref T item)
{
lock (this)
{
if (_TopIndex == _BottomIndex)
{
return false;
}
item = _Items[_TopIndex];
if ((--_TopIndex) == -1)
{
_TopIndex = Capacity - 1;
}
--_Count;
return true;
}
}
/// <summary>
/// 将指定的对象压入堆栈
/// </summary>
/// <param name="item">需要压入的对象</param>
/// <remarks>此操作是内部锁定的,因此多线程操作是安全的</remarks>
public void Push(T item)
{
Console.WriteLine(string.Format("top:{0},bott:{1}", _TopIndex, _BottomIndex));
lock (this)
{
if ((++_TopIndex) == Capacity)
{
_TopIndex = 0;
}
if (_TopIndex == _BottomIndex)
{
if ((++_BottomIndex) == Capacity)
{
_BottomIndex = 0;
}
if (Drop != null)
{
Drop(_Items[_BottomIndex]);
}
--_Count;
}
_Items[_TopIndex] = item;
//_TopIndex++;
++_Count;
}
}
/// <summary>
/// 清除堆栈中的所有对象
/// </summary>
/// <remarks>此操作是内部锁定的,因此多线程操作是安全的</remarks>
public void Clear()
{
lock (this)
{
T t = default(T);
while (_Count > 0)
{
Pop(ref t);
if (Drop != null)
{
Drop(t);
}
}
}
}
}