java 手写 jvm高性能缓存,键值对存储,队列存储,存储超时设置
缓存接口
1 package com.ws.commons.cache; 2 3 import java.util.function.Function; 4 5 public interface ICache { 6 7 void expire(String key, int timeOutSecond); 8 9 void leftPush(String key, Object value); 10 11 void rightPush(String key, Object value); 12 13 void rightPush(String key, Object value, int timeOutSecond); 14 15 <T> T rightPop(String key); 16 17 <T> T leftPop(String key); 18 19 public <T> T computeIfAbsent(String key, int outSecond, Function<String, Object> mappingFunction); 20 21 void put(String key, Object value); 22 23 void put(String key, Object value, int timeOutSecond); 24 25 boolean putIfAbsent(String key, Object value); 26 27 boolean putIfAbsent(String key, Object value, int timeOutSecond); 28 29 <T> T get(String key); 30 31 boolean hasKey(String key); 32 33 void remove(String key); 34 35 <T> T removeAndGet(String key); 36 }
实现类
1 package com.ws.commons.cache; 2 3 import java.time.LocalDateTime; 4 import java.time.format.DateTimeFormatter; 5 import java.util.Iterator; 6 import java.util.Map; 7 import java.util.Map.Entry; 8 import java.util.concurrent.ConcurrentLinkedDeque; 9 import java.util.concurrent.ExecutorService; 10 import java.util.concurrent.Executors; 11 import java.util.concurrent.atomic.AtomicInteger; 12 import java.util.function.Function; 13 14 import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap; 15 import com.googlecode.concurrentlinkedhashmap.Weighers; 16 import com.ws.commons.tool.ThreadTool; 17 18 /** 19 * 本地高性能缓存 20 * 21 * @author 尘无尘 22 * 23 */ 24 public class LocalCache implements ICache { 25 26 private static LocalCache staticInstance; 27 28 public static LocalCache instance() { 29 if (staticInstance != null) { 30 return staticInstance; 31 } else { 32 synchronized (LocalCache.class) { 33 if (staticInstance != null) { 34 return staticInstance; 35 } 36 staticInstance = new LocalCache(); 37 return staticInstance; 38 } 39 } 40 } 41 42 private LocalCache() { 43 } 44 45 /** 46 * 存储最大数据数量,超出该数据量时,删除最新存储的数据 47 */ 48 private static final int MAXCOUNT = 2000; 49 50 /** 51 * 缓存实例 52 */ 53 private static final Map<String, Object> INSTANCE =new ConcurrentLinkedHashMap.Builder<String, Object>() 54 .maximumWeightedCapacity(MAXCOUNT). weigher(Weighers.singleton()).initialCapacity(100).build(); 55 56 /** 57 * 缓存KEY 存储时间记录 58 */ 59 private static final Map<String, Long> KEY_TIME_INSTANCE = new ConcurrentLinkedHashMap.Builder<String, Long>() 60 .maximumWeightedCapacity(MAXCOUNT). weigher(Weighers.singleton()).initialCapacity(100).build(); 61 62 /** 63 * 时间格式化对象 64 */ 65 public static final DateTimeFormatter yyyyMMddHHmmss_FMT = DateTimeFormatter.ofPattern("yyyyMMddHHmmss"); 66 67 68 /** 69 * 清理缓存线程,防止频繁的缓存清理 创建线程消耗性能 70 */ 71 private static final ExecutorService THREAD_POOL = Executors.newCachedThreadPool(); 72 73 /** 74 * 清理缓存时线程做的锁 75 */ 76 private static final AtomicInteger TREAM_CACHE_LOCK = new AtomicInteger(0); 77 78 /** 79 * 缓存清理 轮询一圈等待时长 80 */ 81 private static final int TRIM_INTERIM = 2000; 82 83 /** 84 * 队列存储,在末尾添加元素 85 * 86 * @param key 87 * @param value 88 * @param outSecond 保存时间(秒),超出时间,被清除 89 */ 90 @SuppressWarnings("unchecked") 91 @Override 92 public void rightPush(String key, Object value, int outSecond) { 93 ConcurrentLinkedDeque<Object> linkList = (ConcurrentLinkedDeque<Object>) INSTANCE.get(key); 94 if (linkList == null) { 95 linkList = new ConcurrentLinkedDeque<>(); 96 INSTANCE.put(key, linkList); 97 } 98 KEY_TIME_INSTANCE.put(key, 99 Long.parseLong(LocalDateTime.now().plusSeconds(outSecond).format(yyyyMMddHHmmss_FMT))); 100 linkList.offer(value); 101 LocalCache.streamInstance(); 102 } 103 104 /** 105 * 队列存储,在末尾添加元素 106 * 107 * @param key 108 * @param value 109 */ 110 @SuppressWarnings("unchecked") 111 @Override 112 public void rightPush(String key, Object value) { 113 ConcurrentLinkedDeque<Object> linkList = (ConcurrentLinkedDeque<Object>) INSTANCE.get(key); 114 if (linkList == null) { 115 linkList = new ConcurrentLinkedDeque<>(); 116 INSTANCE.putIfAbsent(key, linkList); 117 } 118 linkList.offer(value); 119 LocalCache.streamInstance(); 120 } 121 122 /** 123 * 队列存储,在开头添加元素 124 * 125 * @param key 126 * @param value 127 */ 128 @SuppressWarnings("unchecked") 129 @Override 130 public void leftPush(String key, Object value) { 131 ConcurrentLinkedDeque<Object> linkList = (ConcurrentLinkedDeque<Object>) INSTANCE.get(key); 132 if (linkList == null) { 133 linkList = new ConcurrentLinkedDeque<>(); 134 INSTANCE.putIfAbsent(key, linkList); 135 } 136 linkList.offerFirst(value); 137 LocalCache.streamInstance(); 138 } 139 140 /** 141 * 删除队列的最后一个元素 142 * 143 * @param key 144 * @return 145 */ 146 @SuppressWarnings("unchecked") 147 @Override 148 public <T> T rightPop(String key) { 149 ConcurrentLinkedDeque<Object> linkList = (ConcurrentLinkedDeque<Object>) INSTANCE.get(key); 150 if (linkList == null) { 151 return null; 152 } 153 return (T) linkList.pollLast(); 154 } 155 156 /** 157 * 删除队列的第一个元素 158 * 159 * @param key 160 * @return 161 */ 162 @SuppressWarnings("unchecked") 163 @Override 164 public <T> T leftPop(String key) { 165 ConcurrentLinkedDeque<Object> linkList = (ConcurrentLinkedDeque<Object>) INSTANCE.get(key); 166 if (linkList == null) { 167 return null; 168 } 169 return (T) linkList.pollFirst(); 170 } 171 172 /** 173 * 174 * @param key 175 * @param outSecond 保存时间(秒),超出时间,被清除 176 * @param value 177 */ 178 @SuppressWarnings("unchecked") 179 @Override 180 public <T>T computeIfAbsent(String key, int outSecond, Function<String, Object> mappingFunction) { 181 T t=(T) INSTANCE.computeIfAbsent(key, mappingFunction); 182 KEY_TIME_INSTANCE.putIfAbsent(key, 183 Long.parseLong(LocalDateTime.now().plusSeconds(outSecond).format(yyyyMMddHHmmss_FMT))); 184 LocalCache.streamInstance(); 185 return t; 186 } 187 188 /** 189 * 190 * @param key 191 * @param value 192 */ 193 @Override 194 public void put(String key, Object value) { 195 INSTANCE.put(key, value); 196 } 197 198 /** 199 * 200 * @param key 201 * @param value 202 * @param outSecond 保存时间(秒),超出时间,被清除 203 */ 204 @Override 205 public void put(String key, Object value, int outSecond) { 206 INSTANCE.put(key, value); 207 KEY_TIME_INSTANCE.put(key, 208 Long.parseLong(LocalDateTime.now().plusSeconds(outSecond).format(yyyyMMddHHmmss_FMT))); 209 LocalCache.streamInstance(); 210 } 211 212 /** 213 * 214 * @param key 215 * @param value 216 * @return 217 */ 218 @Override 219 public boolean putIfAbsent(String key, Object value) { 220 Object result = null; 221 result = INSTANCE.putIfAbsent(key, value); 222 LocalCache.streamInstance(); 223 return result == null; 224 } 225 226 /** 227 * 228 * @param key 229 * @param value 230 * @param outSecond 保存时间(秒),超出时间,被清除 231 * @return 232 */ 233 @Override 234 public boolean putIfAbsent(String key, Object value, int outTimeSecond) { 235 Object result = null; 236 result = INSTANCE.putIfAbsent(key, value); 237 KEY_TIME_INSTANCE.putIfAbsent(key, 238 Long.parseLong(LocalDateTime.now().plusSeconds(outTimeSecond).format(yyyyMMddHHmmss_FMT))); 239 LocalCache.streamInstance(); 240 return result == null; 241 } 242 243 /** 244 * 获取缓存 245 * 246 * @param key 247 * @return 248 */ 249 @SuppressWarnings("unchecked") 250 @Override 251 public <T> T get(String key) { 252 T value = (T) INSTANCE.get(key); 253 if (value == null) { 254 return null; 255 } 256 if (LocalCache.isTimeOut(key)) { 257 INSTANCE.remove(key); 258 KEY_TIME_INSTANCE.remove(key); 259 return null; 260 } else { 261 return value; 262 } 263 } 264 265 @Override 266 public void expire(String key, int timeOutSecond) { 267 KEY_TIME_INSTANCE.put(key, 268 Long.parseLong(LocalDateTime.now().plusSeconds(timeOutSecond).format(yyyyMMddHHmmss_FMT))); 269 } 270 271 /** 272 * 是否含有 273 * 274 * @param key 275 * @return 276 */ 277 @Override 278 public boolean hasKey(String key) { 279 return INSTANCE.containsKey(key); 280 } 281 282 /** 283 * 删除 284 * 285 * @param id 286 * @return 287 */ 288 @Override 289 public void remove(String key) { 290 INSTANCE.remove(key); 291 } 292 293 /** 294 * 删除并返回 295 * 296 * @param id 297 * @return 298 */ 299 @SuppressWarnings("unchecked") 300 @Override 301 public <T> T removeAndGet(String key) { 302 return (T) INSTANCE.remove(key); 303 } 304 305 /** 306 * 整理缓存:<br> 307 * 整理的缓存的线程只能一个,节约资源开销<br> 308 * TRIM_INTERIM<br> 309 */ 310 private static void streamInstance() { 311 312 if (TREAM_CACHE_LOCK.incrementAndGet() > 1) { 313 return; 314 } 315 THREAD_POOL.execute(() -> { 316 long now = Long.parseLong(LocalDateTime.now().format(yyyyMMddHHmmss_FMT)); 317 do { 318 /* 319 * 1、超时缓存清除 320 */ 321 Iterator<Entry<String, Object>> instanceIt = INSTANCE.entrySet().iterator(); 322 while (instanceIt.hasNext()) { 323 String key = instanceIt.next().getKey(); 324 if (LocalCache.isTimeOut(key, now)) { 325 instanceIt.remove(); 326 KEY_TIME_INSTANCE.remove(key); 327 } 328 } 329 330 // /* 331 // * 2、 超容量,从首位开始清除 332 // */ 333 // if (INSTANCE.size() > MAXCOUNT) { 334 // List<String> tempList = new ArrayList<>(); 335 // for (Entry<String, Object> en : INSTANCE.entrySet()) { 336 // tempList.add(en.getKey()); 337 // if (INSTANCE.size() - tempList.size() <= MAXCOUNT) { 338 // tempList.forEach(e -> { 339 // INSTANCE.remove(e); 340 // KEY_TIME_INSTANCE.remove(e); 341 // }); 342 // break; 343 // } 344 // } 345 // } 346 347 ThreadTool.sleep(TRIM_INTERIM); 348 now = Long.valueOf(LocalDateTime.now().format(yyyyMMddHHmmss_FMT)); 349 } while (!INSTANCE.isEmpty()); 350 TREAM_CACHE_LOCK.set(0); 351 }); 352 } 353 354 /** 355 * 判断key对比当前时间是否超时 356 * 357 * @param key 358 * @return 359 */ 360 private static boolean isTimeOut(String key) { 361 long now = Long.parseLong(LocalDateTime.now().format(yyyyMMddHHmmss_FMT)); 362 return LocalCache.isTimeOut(key, now); 363 } 364 365 /** 366 * 367 * 判断key对比now是否超时 368 * 369 * @param key 370 * @param now 371 * @return 372 */ 373 private static boolean isTimeOut(String key, long now) { 374 Long saveTime = KEY_TIME_INSTANCE.get(key); 375 return saveTime == null || saveTime < now; 376 } 377 }