在asp.net中我们可以把我们的一些静态数据通过Cache来缓存,已提高网站性能。下面是msdn上一个使用Cache的例子。其中有可很意思的功能是
我们可以给缓存项指定一个回调,当缓存项被remove的时候将调用回调方法通知我们。我们公司的一个应用使用了这个方法用来缓存对数据库的一些更新,来避免频繁操作数据库已提高性能。当缓存被清除的时候在调用回调吧缓存的数据集中写入数据库。这种方法当并发访问量大大时候就会出现阻塞线程的问题。从而导致cpu狂涨。最后可能耗尽所有线程池线程。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
<
html
>
< Script runat = server language = " C# " >
static bool itemRemoved = false ;
static CacheItemRemovedReason reason;
CacheItemRemovedCallback onRemove = null ;
public void RemovedCallback(String k, Object v, CacheItemRemovedReason r){
itemRemoved = true ;
reason = r;
}
public void AddItemToCache(Object sender, EventArgs e) {
itemRemoved = false ;
onRemove = new CacheItemRemovedCallback( this .RemovedCallback);
if (Cache[ " Key1 " ] == null )
Cache.Add( " Key1 " , " Value 1 " , null , DateTime.Now.AddSeconds( 60 ), TimeSpan.Zero, CacheItemPriority.High, onRemove);
}
public void RemoveItemFromCache(Object sender, EventArgs e) {
if (Cache[ " Key1 " ] != null )
Cache.Remove( " Key1 " );
}
</ Script >
< body >
< Form runat = " server " >
< input type = submit OnServerClick = " AddItemToCache " value = " Add Item To Cache " runat = " server " />
< input type = submit OnServerClick = " RemoveItemFromCache " value = " Remove Item From Cache " runat = " server " />
</ Form >
<% if (itemRemoved) {
Response.Write( " RemovedCallback event raised. " );
Response.Write( " <BR> " );
Response.Write( " Reason: <B> " + reason.ToString() + " </B> " );
}
else {
Response.Write( " Value of cache key: <B> " + Server.HtmlEncode(Cache[ " Key1 " ] as string ) + " </B> " );
}
%>
</ body >
</ html >
< Script runat = server language = " C# " >
static bool itemRemoved = false ;
static CacheItemRemovedReason reason;
CacheItemRemovedCallback onRemove = null ;
public void RemovedCallback(String k, Object v, CacheItemRemovedReason r){
itemRemoved = true ;
reason = r;
}
public void AddItemToCache(Object sender, EventArgs e) {
itemRemoved = false ;
onRemove = new CacheItemRemovedCallback( this .RemovedCallback);
if (Cache[ " Key1 " ] == null )
Cache.Add( " Key1 " , " Value 1 " , null , DateTime.Now.AddSeconds( 60 ), TimeSpan.Zero, CacheItemPriority.High, onRemove);
}
public void RemoveItemFromCache(Object sender, EventArgs e) {
if (Cache[ " Key1 " ] != null )
Cache.Remove( " Key1 " );
}
</ Script >
< body >
< Form runat = " server " >
< input type = submit OnServerClick = " AddItemToCache " value = " Add Item To Cache " runat = " server " />
< input type = submit OnServerClick = " RemoveItemFromCache " value = " Remove Item From Cache " runat = " server " />
</ Form >
<% if (itemRemoved) {
Response.Write( " RemovedCallback event raised. " );
Response.Write( " <BR> " );
Response.Write( " Reason: <B> " + reason.ToString() + " </B> " );
}
else {
Response.Write( " Value of cache key: <B> " + Server.HtmlEncode(Cache[ " Key1 " ] as string ) + " </B> " );
}
%>
</ body >
</ html >
原因是Cache其实是个全局对象,所以对Cache的访问都会在内部通过一个ReaderWriterLock进行同步。在Remove缓存项调用回调方法的时候,由于回调方法又访问数据库。结果导致Remove缓存项长时间的占用锁,导致其他请求无法读取写入缓存,从而阻塞线程池中其他线程。所以缓存项的回调方法不适合调用长时间的操作。最好是移除缓存项后,在自己调用后续操作。避免锁定争用。