我需要一个线程安全缓存来存储一次性类的实例。
这是我写的解决方案:
private class cache<T> where T : IDisposable
{
Func<T> _createFunc;
long livingTicks;
int livingMillisecs;
public cache(Func<T> createFunc, int livingTimeInSec)
{
this.livingTicks = livingTimeInSec * 10000000;
this.livingMillisecs = livingTimeInSec * 1000;
this._createFunc = createFunc;
}
Stack<T> st = new Stack<T>();
public IDisposable BeginUseBlock(out T item)
{
this.actionOccured();
if (st.Count == 0)
item = _createFunc();
else
lock (st)
if (st.Count == 0)
item = _createFunc();
else
item = st.Pop();
return new blockDisposer(this, item);
}
long _lastTicks;
bool _called;
private void actionOccured()
{
if (!_called)
lock (st)
if (!_called)
{
_called = true;
System.Threading.Timer timer = null;
timer = new System.Threading.Timer((obj) =>
{
if ((DateTime.UtcNow.Ticks - _lastTicks) > livingTicks)
{
timer.Dispose();
this.free();
}
},
null, livingMillisecs, livingMillisecs);
}
_lastTicks = DateTime.UtcNow.Ticks;
}
private void free()
{
lock (st)
{
while (st.Count > 0)
st.Pop().Dispose();
_called = false;
}
}
private class blockDisposer : IDisposable
{
T _item;
cache<T> _c;
public blockDisposer(cache<T> c, T item)
{
this._c = c;
this._item = item;
}
public void Dispose()
{
this._c.actionOccured();
lock (this._c.st)
this._c.st.Push(_item);
}
}
}
这是一个示例用途:
class MyClass:IDisposable
{
public MyClass()
{
//expensive work
}
public void Dispose()
{
//free
}
public void DoSomething(int i)
{
}
}
private static Lazy<cache<MyClass>> myCache = new Lazy<cache<MyClass>>(() => new cache<MyClass>(() => new MyClass(), 60), true);//free 60sec. after last call
private static void test()
{
Parallel.For(0, 100000, (i) =>
{
MyClass cl;
using (myCache.Value.BeginUseBlock(out cl))
cl.DoSomething(i);
});
}
我的问题:
修改 我试过@ mjwills的评论。这个表现更好:
ConcurrentStack<T> st = new ConcurrentStack<T>();
public IDisposable BeginUseBlock(out T item)
{
this.actionOccured();
if (!st.TryPop(out item))
item = _createFunc();
return new blockDisposer(this, item);
}
EDIT2: 在我的cas中它不是必需的,但如果我们需要控制堆栈的大小并处理未使用的对象,使用一个单独的计数器,它将使用Interlocked.Increment递增递减(@mjwills)