编码中涉及到资源管理就会经常使用到最近最少使用淘汰原理(LRU),比如说最近打开的文章列表管理、或者游戏中动态加载地图、音乐一样。使用LRU可以提高效率。本文实现了一个完整功能的LRU集合,可用于各种诸如此类需要缓存机制的地方。
/// <summary>
/// 使用最近最少算法进行淘汰的缓存集合,用于缓存数据.
/// 提供了多线程安全访问功能
/// </summary>
/// <remarks>
/// 1、调用方在每使用一个数据之后,调用UpdateRecentlyUsed函数将该数据
/// 置为最近访问。函数会将该条目的读取权值设为最大值。
/// 2、在使用Add或者Insert添加条目时,如果缓存数目已达到设定的CacheSize值,
/// 则会根据删除掉缓存列表中读取权值最小的条目。再进行添加
/// </remarks>
public class LRUCacheList<T> : IList<T>
{
#region Property
/// <summary>
/// 实际存放缓存条目的列表
/// </summary>
private List<T> m_listData;
/// <summary>
/// 存放与m_listData依次对应条目的最近读取记录
/// </summary>
private List<uint> m_listReadWeight;
/// <summary>
/// 当前最大的读取记录权值,用来计算下一个读取值
/// </summary>
private uint m_iMaxWeight;
/// <summary>
/// 一个无符号整数的最大值
/// </summary>
private const uint c_MaxWeight = 0xffffffff;
private Object m_lockObj = new object();
/// <summary>
/// 读取和设置缓存大小,指定最多缓存的对象数目
/// </summary>
public int CacheSize { get; set; }
#endregion
#region Method
/// <summary>
///
/// </summary>
/// <param name="cacheSize">缓存数目</param>
public LRUCacheList(int cacheSize)
{
m_listData = new List<T>(cacheSize);
m_listReadWeight = new List<uint>(cacheSize);
CacheSize = cacheSize;
}
/// <summary>
/// 移除掉最近最少使用的条目
/// </summary>
protected void RemoveLeastRecentlyUsed()
{
lock (m_lockObj)
{
uint min = c_MaxWeight;
int minIndex = -1;
for (int i = 0; i < m_listReadWeight.Count; i++)
{
if (m_listReadWeight[i] < min)
{
min = m_listReadWeight[i];
minIndex = i;
}
}
if (minIndex != -1)
{
m_listReadWeight.RemoveAt(minIndex);
m_listData.RemoveAt(minIndex);
}
}
}
/// <summary>
/// 更新指定位置的权重值为最近访问
/// </summary>
/// <param name="index"></param>
public void UpdateRecentlyUsed(T item)
{
lock (m_lockObj)
{
int index = m_listData.IndexOf(item);
if (index != -1)
UpdateRecentlyUsed(index);
}
}
/// <summary>
/// 更新指定位置的权重值为最近访问
/// </summary>
/// <param name="index"></param>
public void UpdateRecentlyUsed(int index)
{
m_listReadWeight[index] = NextMaxWeight();
}
/// <summary>
/// 清除掉所有缓存的内容
/// </summary>
public void Clear()
{
lock (m_lockObj)
{
if (m_listData != null)
m_listData.Clear();
if (m_listReadWeight != null)
m_listReadWeight.Clear();
m_iMaxWeight = 0;
}
}
/// <summary>
/// 获取并设置下一个最大的权重值
/// </summary>
/// <returns></returns>
public uint NextMaxWeight()
{
lock (m_lockObj)
{
//到达最大值重置
if (m_iMaxWeight == c_MaxWeight - 1)
{
m_iMaxWeight = 0;
for (int i = 0; i < m_listReadWeight.Count; i++)
{
m_listReadWeight[i] = 0;
}
}
m_iMaxWeight++;
return m_iMaxWeight;
}
}
/// <summary>
/// 添加一个条目并设置为最近访问
/// </summary>
/// <param name="item"></param>
public void AddRecently(T item)
{
lock (m_lockObj)
{
while (CacheSize > 0 && m_listData.Count >= CacheSize)
RemoveLeastRecentlyUsed();
m_listData.Add(item);
m_listReadWeight.Add(NextMaxWeight());
}
}
/// <summary>
/// 插入一个条目并设置为最近访问
/// </summary>
/// <param name="index"></param>
/// <param name="item"></param>
public void InsertRecently(int index, T item)
{
lock (m_lockObj)
{
while (CacheSize > 0 && m_listData.Count >= CacheSize)
RemoveLeastRecentlyUsed();
m_listData.Insert(index, item);
m_listReadWeight.Insert(index, NextMaxWeight());
}
}
#endregion
#region 实现IList<T> 接口
public void Add(T item)
{
lock (m_lockObj)
{
while (CacheSize > 0 && m_listData.Count >= CacheSize)
RemoveLeastRecentlyUsed();
m_listData.Add(item);
m_listReadWeight.Add(0);
}
}
/// <summary>
///
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public int IndexOf(T item)
{
return m_listData.IndexOf(item);
}
public void Insert(int index, T item)
{
lock (m_lockObj)
{
while (CacheSize > 0 && m_listData.Count >= CacheSize)
RemoveLeastRecentlyUsed();
m_listData.Insert(index, item);
m_listReadWeight.Insert(index, 0);
}
}
public void RemoveAt(int index)
{
lock (m_lockObj)
{
m_listData.RemoveAt(index);
m_listReadWeight.RemoveAt(index);
}
}
public T this[int index]
{
get
{
return m_listData[index];
}
set
{
m_listData[index] = value;
}
}
public bool Contains(T item)
{
return m_listData.Contains(item);
}
public void CopyTo(T[] array, int arrayIndex)
{
m_listData.CopyTo(array, arrayIndex);
}
public int Count
{
get { return m_listData.Count; }
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(T item)
{
lock (m_lockObj)
{
int index = m_listData.IndexOf(item);
if (index != -1)
m_listReadWeight.RemoveAt(index);
return m_listData.Remove(item);
}
}
public IEnumerator<T> GetEnumerator()
{
return m_listData.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return m_listData.GetEnumerator();
}
#endregion
}