关于全局缓存的一种简单实现方法

缓存,在.Net系统开发中,经常使用到。如果,让你自己去实现,你会怎么做呢。

开始编码前思考:

 1、肯定 是要 根据 key 去查询对应value,so 应该是List<KeyValuePair> 这类集合做缓存载体;

 2、肯定是要全局公用,so 缓存的列表应该唯一;

 3、应该有支持并发的能力,so 实现过程中肯定要加锁; 

 4、应该可以支持过期,自动 or 手动,so 应该 可以添加过期时间;

好的,基于以上3点,设计的类应该需要是单体(单例)模式,查询、删除key时应该lock 缓存载体,可以有定时清除过期缓存项的能力;

  1     public static class CacheHelper
  2     {
  3         private static int RestoreCacheCount = 20000;
  4         private static DateTime LastRestoreCachTime;
  5         private static Dictionary<string, MyCacheEntity> CacheEntryDictionary;
  6         private static readonly object objLock = new object();
  7 
  8         static CacheHelper()
  9         {
 10             if (CacheEntryDictionary == null)
 11             {
 12                 lock (objLock)
 13                 {
 14                     if (CacheEntryDictionary == null)
 15                     {
 16                         CacheEntryDictionary = new Dictionary<string, MyCacheEntity>();
 17                         LastRestoreCachTime = DateTime.Now;
 18                         System.Threading.Tasks.Task.Factory.StartNew(() => RestoreCache());
 19                     }
 20                 }
 21             }
 22         }
 23 
 24         public static void Set<T>(string key, T entity, double timeout)
 25         {
 26             if (string.IsNullOrEmpty(key))
 27                 throw new ArgumentNullException(nameof(key));
 28             if (entity == null)
 29                 throw new ArgumentNullException(nameof(entity));
 30             var expiredTime = DateTime.Now.AddSeconds(timeout);
 31             lock (objLock)
 32             {
 33                 if (DateTime.Now.Subtract(expiredTime).TotalSeconds >= 0)
 34                 {
 35                     if (CacheEntryDictionary.ContainsKey(key))
 36                         CacheEntryDictionary.Remove(key);
 37                 }
 38                 else
 39                 {
 40                     CacheEntryDictionary[key] = new MyCacheEntity { Value = entity, ExpiredTime = expiredTime };
 41                 }
 42             }
 43         }
 44 
 45         public static T Get<T>(string key)
 46         {
 47             if (string.IsNullOrEmpty(key))
 48                 throw new ArgumentNullException(nameof(key));
 49             var value = default(T);
 50             lock (objLock)
 51             {
 52                 var exist = CacheEntryDictionary.ContainsKey(key);
 53                 if (!exist) return value;
 54                 var obj = CacheEntryDictionary[key];
 55                 if (obj == null)
 56                 {
 57                     CacheEntryDictionary.Remove(key);
 58                     return value;
 59                 }
 60                 if (obj.ExpiredTime == DateTime.MinValue || DateTime.Now.Subtract(obj.ExpiredTime).TotalSeconds >= 0)
 61                 {
 62                     CacheEntryDictionary.Remove(key);
 63                     return value;
 64                 }
 65                 return (T)Convert.ChangeType(obj.Value, typeof(T));
 66             }
 67         }
 68 
 69         public static void Remove(string key)
 70         {
 71             if (string.IsNullOrEmpty(key))
 72                 throw new ArgumentNullException(nameof(key));
 73             try
 74             {
 75                 lock (objLock)
 76                 {
 77                     var exist = CacheEntryDictionary.ContainsKey(key);
 78                     if (!exist) return;
 79                     CacheEntryDictionary.Remove(key);
 80                 }
 81             }
 82             catch (Exception e)
 83             {
 84                 throw e;
 85             }
 86         }
 87 
 88         public static void Clear()
 89         {
 90             try
 91             {
 92                 lock (objLock)
 93                 {
 94                     CacheEntryDictionary.Clear();
 95                     LastRestoreCachTime = DateTime.Now;
 96                 }
 97             }
 98             catch (Exception e)
 99             {
100                 throw e;
101             }
102         }
103 
104         public static int Count => CacheEntryDictionary?.Count ?? 0;
105 
106         private static void RestoreCache()
107         {
108             while (true)
109             {
110                 if (CacheEntryDictionary.Keys.Count < 1) return;
111                 try
112                 {
113                     bool isEnter = false;
114                     Monitor.TryEnter(CacheEntryDictionary, 1000, ref isEnter);
115                     if (isEnter)
116                     {
117                         if (CacheEntryDictionary.Count > RestoreCacheCount && DateTime.Now.Subtract(LastRestoreCachTime).TotalMinutes > 1)
118                         {
119                             var keys = CacheEntryDictionary.Where(m => m.Value.ExpiredTime < DateTime.Now).Select(m => m.Key).ToList();
120                             foreach (var key in keys)
121                             {
122                                 CacheEntryDictionary.Remove(key);
123                             }
124                             LastRestoreCachTime = DateTime.Now;
125                         }
126                     }
127                 }
128                 finally
129                 {
130                     Monitor.Exit(CacheEntryDictionary);
131                 }
132                 Thread.Sleep(1000 * 6);
133             }
134         }
135     }
136     public class MyCacheEntity
137     {
138         public object Value { get; set; }
139         public DateTime ExpiredTime { get; set; }
140     }

如果想要 key 不区分大小写,可以 在构造函数中 设置

 CacheEntryDictionary = new Dictionary<string, MyCacheEntity>(StringComparer.OrdinalIgnoreCase);

你可能会有疑问,为什么不用 线程安全的字典 ConcurrentDictionary 呢?

当然可以将 Dictionary 改为 ConcurrentDictionary 没有任何问题,只是我想要自己手动实现加减速的过程;ConcurrentDictionary 字典内部也是调用Monitor 进行的加减锁的过程;

如果想要在缓存中实现 缓存文件,并且文件内容改变同步修改缓存的内容呢?

修改 以上方法 加入

 1、添加缓存文件

 2、刷新缓存文件内容,定时过期、监控文件内容更改等;

相关代码;

  1     public static class CacheHelper
  2     {
  3         private static int RestoreCacheCount = 20000;
  4         private static DateTime LastRestoreCachTime;
  5         private static Dictionary<string, MyCacheEntity> CacheEntryDictionary;
  6         private static readonly object objLock = new object();
  7         private static Dictionary<string, MyCacheEntity> FileCacheEntryDictionary;
  8 
  9         static CacheHelper()
 10         {
 11             if (CacheEntryDictionary == null)
 12             {
 13                 lock (objLock)
 14                 {
 15                     if (CacheEntryDictionary == null)
 16                     {
 17                         CacheEntryDictionary = new Dictionary<string, MyCacheEntity>(StringComparer.OrdinalIgnoreCase);
 18                         LastRestoreCachTime = DateTime.Now;
 19                         System.Threading.Tasks.Task.Factory.StartNew(() => RestoreCache());
 20                     }
 21                     if (FileCacheEntryDictionary == null)
 22                     {
 23                         FileCacheEntryDictionary = new Dictionary<string, MyCacheEntity>();
 24                         System.Threading.Tasks.Task.Factory.StartNew(() => ReFreshFileCache());
 25                     }
 26                 }
 27             }
 28         }
 29 
 30         public static void Set<T>(string key, T entity, double timeout)
 31         {
 32             if (string.IsNullOrEmpty(key))
 33                 throw new ArgumentNullException(nameof(key));
 34             if (entity == null)
 35                 throw new ArgumentNullException(nameof(entity));
 36             var expiredTime = DateTime.Now.AddSeconds(timeout);
 37             lock (objLock)
 38             {
 39                 if (DateTime.Now.Subtract(expiredTime).TotalSeconds >= 0)
 40                 {
 41                     if (CacheEntryDictionary.ContainsKey(key))
 42                         CacheEntryDictionary.Remove(key);
 43                 }
 44                 else
 45                 {
 46                     CacheEntryDictionary[key] = new MyCacheEntity { Value = entity, ExpiredTime = expiredTime };
 47                 }
 48             }
 49         }
 50 
 51         public static void SetFile(string key, string filePath, Encoding encoding, double timeout)
 52         {
 53             if (string.IsNullOrEmpty(key))
 54                 throw new ArgumentNullException(nameof(key));
 55             if (!File.Exists(filePath))
 56                 throw new FileNotFoundException(filePath);
 57             var expiredTime = DateTime.Now.AddSeconds(timeout);
 58             lock (objLock)
 59             {
 60                 if (DateTime.Now.Subtract(expiredTime).TotalSeconds >= 0)
 61                 {
 62                     if (CacheEntryDictionary.ContainsKey(key))
 63                         CacheEntryDictionary.Remove(key);
 64                 }
 65                 else
 66                 {
 67                     FileInfo fileInfo = new FileInfo(filePath);
 68                     string value = null;
 69                     using (var stream = new StreamReader(filePath, encoding))
 70                     {
 71                         value = stream.ReadToEnd();
 72                     }
 73                     CacheEntryDictionary[key] = new MyCacheEntity
 74                     {
 75                         Value = value,
 76                         ExpiredTime = expiredTime
 77                     };
 78                     FileCacheEntryDictionary[key] = new MyCacheEntity
 79                     {
 80                         Value = new FileCacheOption
 81                         {
 82                             FilePath = filePath,
 83                             FileSize = fileInfo.Length,
 84                             LastWriteTime = fileInfo.LastWriteTime,
 85                             Encoding = encoding
 86                         },
 87                         ExpiredTime = expiredTime
 88                     };
 89                 }
 90             }
 91         }
 92 
 93         public static T Get<T>(string key)
 94         {
 95             if (string.IsNullOrEmpty(key))
 96                 throw new ArgumentNullException(nameof(key));
 97             var value = default(T);
 98             lock (objLock)
 99             {
100                 var exist = CacheEntryDictionary.ContainsKey(key);
101                 if (!exist) return value;
102                 var obj = CacheEntryDictionary[key];
103                 if (obj == null)
104                 {
105                     CacheEntryDictionary.Remove(key);
106                     return value;
107                 }
108                 if (obj.ExpiredTime == DateTime.MinValue || DateTime.Now.Subtract(obj.ExpiredTime).TotalSeconds >= 0)
109                 {
110                     CacheEntryDictionary.Remove(key);
111                     return value;
112                 }
113                 return (T)Convert.ChangeType(obj.Value, typeof(T));
114             }
115         }
116 
117         public static void Remove(string key)
118         {
119             if (string.IsNullOrEmpty(key))
120                 throw new ArgumentNullException(nameof(key));
121             try
122             {
123                 lock (objLock)
124                 {
125                     var exist = CacheEntryDictionary.ContainsKey(key);
126                     if (!exist) return;
127                     CacheEntryDictionary.Remove(key);
128                     if (FileCacheEntryDictionary.ContainsKey(key))
129                         FileCacheEntryDictionary.Remove(key);
130                 }
131             }
132             catch (Exception e)
133             {
134                 throw e;
135             }
136         }
137 
138         public static void Clear()
139         {
140             try
141             {
142                 lock (objLock)
143                 {
144                     CacheEntryDictionary.Clear();
145                     FileCacheEntryDictionary.Clear();
146                     LastRestoreCachTime = DateTime.Now;
147                 }
148             }
149             catch (Exception e)
150             {
151                 throw e;
152             }
153         }
154 
155         public static int Count => CacheEntryDictionary?.Count ?? 0;
156 
157         private static void RestoreCache()
158         {
159             while (true)
160             {
161                 if (CacheEntryDictionary.Keys.Count < 1) return;
162                 try
163                 {
164                     bool isEnter = false;
165                     Monitor.TryEnter(CacheEntryDictionary, 1000, ref isEnter);
166                     if (isEnter)
167                     {
168                         if (CacheEntryDictionary.Count > RestoreCacheCount && DateTime.Now.Subtract(LastRestoreCachTime).TotalMinutes > 1)
169                         {
170                             var keys = CacheEntryDictionary.Where(m => m.Value.ExpiredTime < DateTime.Now).Select(m => m.Key).ToList();
171                             foreach (var key in keys)
172                             {
173                                 CacheEntryDictionary.Remove(key);
174                             }
175                             LastRestoreCachTime = DateTime.Now;
176                         }
177                     }
178                 }
179                 finally
180                 {
181                     Monitor.Exit(CacheEntryDictionary);
182                 }
183                 184                 Thread.Sleep(1000 * 6);
185             }
186         }
187 
188         private static void ReFreshFileCache()
189         {
190             while (true)
191             {
192                 if (FileCacheEntryDictionary.Keys.Count < 1) return;
193                 try
194                 {
195                     bool isEnter = false;
196                     Monitor.TryEnter(FileCacheEntryDictionary, 100, ref isEnter);
197                     if (isEnter && FileCacheEntryDictionary.Keys.Count > 0)
198                     {
199                         var keys = FileCacheEntryDictionary.Keys.ToList();
200                         foreach (var key in keys)
201                         {
202                             var value = FileCacheEntryDictionary[key];
203                             if (value.ExpiredTime <= DateTime.Now)
204                             {
205                                 FileCacheEntryDictionary.Remove(key);
206                                 continue;
207                             }
208                             var fileCacheOption = value.Value as FileCacheOption;
209                             if (fileCacheOption == null)
210                             {
211                                 FileCacheEntryDictionary.Remove(key);
212                                 continue;
213                             }
214                             if (!File.Exists(fileCacheOption.FilePath))
215                             {
216                                 FileCacheEntryDictionary.Remove(key);
217                                 CacheEntryDictionary.Remove(key);
218                                 continue;
219                             }
220                             FileInfo fileInfo = new FileInfo(fileCacheOption.FilePath);
221                             if (fileInfo.Length != fileCacheOption.FileSize || fileInfo.LastWriteTime != fileCacheOption.LastWriteTime)
222                             {
223                                 fileCacheOption.LastWriteTime = fileInfo.LastWriteTime;
224                                 fileCacheOption.FileSize = fileInfo.Length;
225                                 FileCacheEntryDictionary[key] = new MyCacheEntity { Value = fileCacheOption, ExpiredTime = value.ExpiredTime };
226                                 using (var stream = new StreamReader(fileCacheOption.FilePath, fileCacheOption.Encoding))
227                                 {
228                                     Set(key, stream.ReadToEnd(), (int)value.ExpiredTime.Subtract(DateTime.Now).TotalSeconds);
229                                 }
230                             }
231                         }
232                     }
233                 }
234                 finally
235                 {
236                     Monitor.Exit(FileCacheEntryDictionary);
237                 }
238                
239                 Thread.Sleep(100);
240             }
241         }
242     }
243     public class MyCacheEntity
244     {
245         public object Value { get; set; }
246         public DateTime ExpiredTime { get; set; }
247     }
248 
249     public class FileCacheOption
250     {
251         public string FilePath { get; set; }
252         public long FileSize { get; set; }
253         public DateTime LastWriteTime { get; set; }
254         public Encoding Encoding { get; set; }
255     }

其实上边的文件监控 可以用 FileSystemWatcher 来做文件监控,。只是我做测试的时候,在触发多个事件读取文件内容时,会报文件被占用,然后就是在centos 下,编辑文件后保存时,会同时触发 Created、Changed 两个事件,在windows 下不存在这种情况,可能是我的方法设置有问题吧。

转载于:https://www.cnblogs.com/flyfishing/articles/Global_CacheHelper.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/349600.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Lombok–您绝对应该尝试一下

Lombok在Java生态系统中并不是什么新鲜事物&#xff0c;但是我必须承认&#xff0c;直到我尝试使用它或被“确信”尝试它之前&#xff0c;我总是低估了它的价值。 我发现添加一个库来生成代码的价值并不高&#xff0c;这些库可以被当今的任何现代IDE轻松生成。 因此&#xff0c…

苹果手机透明桌面_原来苹果手机辨别真假这么简单!查看桌面1个图标,就能轻松分辨...

要说哪个品牌的手机贵&#xff0c;大家想到的肯定是苹果手机啦&#xff0c;所以说很多朋友都害怕自己买到假货。其实分辨苹果手机是不是正品很简单&#xff0c;只需学会这两个方法&#xff0c;就能辨别出手机的真假哦。一、从细节入手1.桌面时钟不知道大家发现没&#xff0c;iP…

NOIP模拟测试34「次芝麻·呵呵呵·长寿花」

次芝麻 题解 大力打表,发现快速幂, 例如初始$5$ $6$,那么第一次就是$5*2\%1110$,$6*2\%111$. 代码 #include<bits/stdc.h> using namespace std; #define ll long long ll n,m,k,d; ll g(ll x,ll k,ll s1){for(;k;k>>1,xx*x%d)if(k&1) ss*x%d;return s; } int …

Java Bean验证基础

这篇文章总结了一些简单易用的示例&#xff0c;这些示例说明了您想使用Java Beans Validation API&#xff08;JSR 349&#xff0c;JSR 303&#xff09;进行的最常见操作。 记住&#xff0c;Beans Validation独立于Java EE。 尽管它是作为Java EE兼容服务器的一部分内置的&…

NOIP模拟测试「简单的区间·简单的玄学·简单的填数·简单的序列」

简单的区间 $update$ 终于$AC$了 找到$(sum[r]sum[l](sum表示以中间点为基准的sum)-mx)\%k0$的点 注意这里$sum$表示是以$mid$为基准点,(即$sum[l]$为后缀和,$sum[r]$为前缀和) 回忆$(sum[r]-sum[l])\%k0$这个经典问题做法(入阵曲简化版),开桶,桶里维护$sum[l]\%k$,那么$r$贡献…

苹果手机变卡了怎么解决_iOS 变卡怎么解决?一招搞定!无需刷机

iOSiOS 因为其优秀的底层交互逻辑&#xff0c;能让一部 iPhone 在不跨版本更新系统的前提下&#xff0c;至少保证 2 年内如新机般流畅。两年之后呢&#xff1f;你是否为手中的老将渐衰而苦恼过&#xff1f;本人对手机的流畅度十分敏感&#xff0c;可以说到了极致。付款时&#…

NOIP模拟测试38「金·斯诺·赤」

金 辗转相减见祖宗 高精 #include<bits/stdc.h> using namespace std; #define A 2000 #define P 1 #define N 10 #define ll long long ll n,T; char sjdfj[A]; struct bignum {ll n[A],l;bignum(){l1,memset(n,0,sizeof(n));}void clear(){while(l>1&&!n[l-…

什么是JSON处理(JSON-P API)?

Java EE中的JSON-P简介 JSON处理1.0&#xff08; JSR 353 &#xff09;的Java API是一个低级&#xff0c;轻量级的JSON解析器和生成器&#xff0c;它提供了在属性和值级别上操作JSON数据的能力。 JSR 353提供了两种JSON处理模型&#xff1a; 对象模型和流模型。 两种模型都可以…

电视机原理图_电工电气,如何看电气原理图和接线图,如何设计图纸?

电气图纸一般可分为两大类&#xff0c;一类为电力电气图&#xff0c;它主要是表述电能的传输、分配和转换&#xff0c;如电网电气图、电厂电气控制图等。另一类为电子电气图&#xff0c;它主要表述电子信息的传递、处理&#xff1b;如电视机电气原理图。本文主要谈电力电气图的…

NOIP模拟测试39,思维禁锢专场「工业题·玄学题·卡常题」

工业题 题解 抱歉,题解没时间写了 代码 #include<bits/stdc.h> using namespace std; #define ll long long #define A 6666666 #define mod 998244353 ll jie[A],ni[A],acnt[A],bcnt[A]; ll fheng[A],fshu[A]; ll n,m,a,b; ll meng(ll x,ll k){ll ans1;for(;k;k>>…

ubuntu 如何登录远程服务器_VSCode远程登录云服务器、树莓派实现在线调试代码...

在PyCon2019大会上&#xff0c;微软发布了VSCode Remote&#xff0c;开启了远程开发的新时代&#xff01;Remote可以帮助开发者在容器、物理机器或虚拟机&#xff0c;以及WSL上实现无缝的远程开发。通过安装Remote Development Extension Pack&#xff0c;开发者可以快速上手远…

macosx jdk_MacOSX环境上的多个Java JDK

macosx jdk同样&#xff0c;这是在Mac&#xff08;OSX 10.8.x &#xff09;上配置Java开发环境的一个小技巧。 如果您现在真的开始&#xff0c;我建议您阅读我以前的文章之一 &#xff0c;这是一种快速干净的方法&#xff08;我想&#xff09;来设置环境变量并开始Java编码。 今…

屏幕方向读取与锁定:Screen Orientation API(转)

什么是 Screen Orientation API Screen Orientation API 为 Web 应用提供了读取设备当前屏幕方向、旋转角度、锁定旋转方向、获取方向改变事件的能力。使得特定应用在屏幕方向方面增强用户体验&#xff0c;如视频和游戏。该标准目前处于工作组草案状态&#xff0c;最近一个修改…

scenebuilder各控件属性介绍_Flutter 全栈式——基础控件

在Flutter中&#xff0c;UI小控件有两种设计风格&#xff0c;一种是Material设计&#xff0c;这是安卓的官方设计风格&#xff0c;另一种则是Cupertino风格&#xff0c;是iOS的官方设计风格。因此&#xff0c;当遇到带有这两个单词开头的控件时&#xff0c;我们应该明确他们表达…

正义联盟的Spring靴

正义联盟的黑暗时代已经来临&#xff0c;强大的Darkseid即将征服人类。 蝙蝠侠在《神力女超人》的帮助下&#xff0c;努力使联盟与一个关键方面失联。 适当的正义联盟成员管理系统。 由于时间不在他们身边&#xff0c;他们不想经历繁琐的过程&#xff0c;从头开始用他们需要的所…

Fetch

fetch是一种HTTP数据请求的方式&#xff0c;是XMLHttpRequest的一种替代方案。fetch不是ajax的进一步封装&#xff0c;而是原生js。Fetch函数就是原生js&#xff0c;没有使用XMLHttpRequest对象。 ajax 使用步骤1.创建XmlHttpRequest对象2.调用open方法设置基本请求信息3.设置发…

boost安装_Centos安装MySQL

安装MySQLMySQL 各版本介绍视频观看:https://www.bilibili.com/video/BV1ap4y1i75jMySQL 官网:https://www.mysql.com/cn/MySQL Community Server社区版本&#xff0c;开源免费&#xff0c;但不提供官方技术支持。MySQL Enterprise Edition 企业版本&#xff0c;需付费&#xf…

选择Java加密算法第3部分–公钥/私钥非对称加密

抽象 这是涵盖Java加密算法的三部分博客系列的第3部分。 本系列介绍如何实现以下目标&#xff1a; 使用SHA–512散列 使用AES–256的单密钥对称加密 RSA–4096 这第三篇文章详细介绍了如何实现非对称的RSA-4096公/私钥加密。 让我们开始吧。 免责声明 这篇文章仅供参考。 …

Error: Cannot find module '@babel/core'

官方默认babel-loader需要搭配最新版本babel 更新到最高版本: npm install -D babel-loader babel/core babel/preset-env webpack 转载于:https://www.cnblogs.com/nocry/p/11493363.html

javabeans_膨胀的JavaBeans –不要在您的API中添加“ Getters”

javabeans我已经最近在博客的想法的JavaBeans™如何可以扩展以减少在Java世界中&#xff0c;这被广泛接受的公约设立的膨胀。 该文章在DZone上重新发布&#xff0c;并在这里获得了颇具争议的反馈&#xff08;例如&#xff0c;大多数试图将一些新想法带入Java世界的想法&#xf…