标准的缓存机制需要开发者填充它然后让它自动无效后内容过期。在随后的方法缓存机制将自动填充以及自动失效。
protected abstract T GetData();// where T is the type of data you want to cache
protected virtual TimeSpan GetLifetime();
你可
通过
以下
签名
的静态
属性访问
缓存的数据
:
public static T Data { get ;}
你可以通过表态方法强制更新内存:
public static void Invalidate();
- 当第一次使用缓存:当数据没有加载完全时所有客户线程必须阻塞.
- 当缓存的数据过期 或者更新缓存必须 使内容更新.
- 在后台必须只有一个线程能够更新缓存数据.
public abstract class Cache<U,T>
where U : Cache<U,T>, new()
where T : class
{
protected abstract T GetData();
protected virtual TimeSpan GetLifetime() { return TimeSpan.FromMinutes(10); }
protected Cache() { }
enum State
{
Empty,
OnLine,
Expired,
Refreshing
}
static U Instance = new U();
static T InMemoryData { get; set; }
static volatile State CurrentState = State.Empty;
static volatile object StateLock = new object();
static volatile object DataLock = new object();
static DateTime RefreshedOn = DateTime.MinValue;
public static T Data
{
get
{
switch (CurrentState)
{
case State.OnLine: // Simple check on time spent in cache vs lifetime
var timeSpentInCache = (DateTime.UtcNow - RefreshedOn);
if (timeSpentInCache > Instance.GetLifetime())
{
lock (StateLock)
{
if (CurrentState == State.OnLine) CurrentState = State.Expired;
}
}
break;
case State.Empty: // Initial load : blocking to all callers
lock (DataLock)
{
lock (StateLock)
{
if (CurrentState == State.Empty)
{
InMemoryData = Instance.GetData(); // actually retrieve data from inheritor
RefreshedOn = DateTime.UtcNow;
CurrentState = State.OnLine;
}
}
}
break;
case State.Expired: // The first thread getting here launches an asynchronous refresh
lock (StateLock)
{
if (CurrentState == State.Expired)
{
CurrentState = State.Refreshing;
Task.Factory.StartNew(() => Refresh());
}
}
break;
}
lock (DataLock)
{
if (InMemoryData != null) return InMemoryData;
}
return Data;
}
}
static void Refresh()
{
if (CurrentState == State.Refreshing)
{
var dt = Instance.GetData(); // actually retrieve data from inheritor
lock (StateLock)
{
lock (DataLock)
{
RefreshedOn = DateTime.UtcNow;
CurrentState = State.OnLine;
InMemoryData = dt;
}
}
}
}
public static void Invalidate()
{
lock (StateLock)
{
RefreshedOn = DateTime.MinValue;
CurrentState = State.Expired;
}
}
}
实例:
public class MyExpensiveListOfStrings : Cache<MyExpensiveListOfStrings, List<string>>
{
protected override List<string> GetData()
{
System.Diagnostics.Trace.WriteLine("Getting fresh data...");
// Make it a really expensive list of string...
Thread.Sleep(3000);
List<string> result = new List<string>();
for (int i = 0; i < 10000; i++)
{
result.Add("Data - " + i.ToString());
}
return result;
}
protected override TimeSpan GetLifetime()
{
// Refreshed asynchronously when has spent more than 30 seconds in memory
return TimeSpan.FromSeconds(30);
}
}
Example:
程序会创建十人线程访问缓存的字符串.
所有线程阻塞当第一次缓存数据时.
Then the cache will refresh in the background every 30 seconds or will be invalidated when you press the space bar. No threads will be blocked anymore.
在后台每30分种后更新缓存或者你按下空格.没有线程会被阻塞。
class Program
{
static void Main(string[] args)
{
for (int i =0;i<10; i++)
{
var t = Task.Factory.StartNew(() =>
{
while (true)
{
System.Diagnostics.Trace.WriteLine("Looping " +
Thread.CurrentThread.ManagedThreadId + " -> " +
MyExpensiveListOfStrings.Data.Count);
Thread.Sleep(50);
}
});
}
ConsoleKeyInfo key = Console.ReadKey();
while (key.Key == ConsoleKey.Spacebar)
{
MyExpensiveListOfStrings.Invalidate();
key = Console.ReadKey();
}
}
}
原文地址