java 手写 jvm高性能缓存
java 手写 jvm高性能缓存,键值对存储,队列存储,存储超时设置
缓存接口
package com.ws.commons.cache; import java.util.function.Function; public interface ICache { void expire(String key, int timeOutSecond); void leftPush(String key, Object value); void rightPush(String key, Object value); void rightPush(String key, Object value, int timeOutSecond); <T> T rightPop(String key); <T> T leftPop(String key); public <T> T computeIfAbsent(String key, int outSecond, Function<String, Object> mappingFunction); void put(String key, Object value); void put(String key, Object value, int timeOutSecond); boolean putIfAbsent(String key, Object value); boolean putIfAbsent(String key, Object value, int timeOutSecond); <T> T get(String key); boolean hasKey(String key); void remove(String key); <T> T removeAndGet(String key);
}
实现类
package com.ws.commons.cache; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function; import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap;
import com.googlecode.concurrentlinkedhashmap.Weighers;
import com.ws.commons.tool.ThreadTool; /**
* 本地高性能缓存
*
* @author 尘无尘
*
*/
public class LocalCache implements ICache { private static LocalCache staticInstance; public static LocalCache instance() {
if (staticInstance != null) {
return staticInstance;
} else {
synchronized (LocalCache.class) {
if (staticInstance != null) {
return staticInstance;
}
staticInstance = new LocalCache();
return staticInstance;
}
}
} private LocalCache() {
} /**
* 存储最大数据数量,超出该数据量时,删除最新存储的数据
*/
private static final int MAXCOUNT = 2000; /**
* 缓存实例
*/
private static final Map<String, Object> INSTANCE =new ConcurrentLinkedHashMap.Builder<String, Object>()
.maximumWeightedCapacity(MAXCOUNT). weigher(Weighers.singleton()).initialCapacity(100).build(); /**
* 缓存KEY 存储时间记录
*/
private static final Map<String, Long> KEY_TIME_INSTANCE = new ConcurrentLinkedHashMap.Builder<String, Long>()
.maximumWeightedCapacity(MAXCOUNT). weigher(Weighers.singleton()).initialCapacity(100).build(); /**
* 时间格式化对象
*/
public static final DateTimeFormatter yyyyMMddHHmmss_FMT = DateTimeFormatter.ofPattern("yyyyMMddHHmmss"); /**
* 清理缓存线程,防止频繁的缓存清理 创建线程消耗性能
*/
private static final ExecutorService THREAD_POOL = Executors.newCachedThreadPool(); /**
* 清理缓存时线程做的锁
*/
private static final AtomicInteger TREAM_CACHE_LOCK = new AtomicInteger(0); /**
* 缓存清理 轮询一圈等待时长
*/
private static final int TRIM_INTERIM = 2000; /**
* 队列存储,在末尾添加元素
*
* @param key
* @param value
* @param outSecond 保存时间(秒),超出时间,被清除
*/
@SuppressWarnings("unchecked")
@Override
public void rightPush(String key, Object value, int outSecond) {
ConcurrentLinkedDeque<Object> linkList = (ConcurrentLinkedDeque<Object>) INSTANCE.get(key);
if (linkList == null) {
linkList = new ConcurrentLinkedDeque<>();
INSTANCE.put(key, linkList);
}
KEY_TIME_INSTANCE.put(key,
Long.parseLong(LocalDateTime.now().plusSeconds(outSecond).format(yyyyMMddHHmmss_FMT)));
linkList.offer(value);
LocalCache.streamInstance();
} /**
* 队列存储,在末尾添加元素
*
* @param key
* @param value
*/
@SuppressWarnings("unchecked")
@Override
public void rightPush(String key, Object value) {
ConcurrentLinkedDeque<Object> linkList = (ConcurrentLinkedDeque<Object>) INSTANCE.get(key);
if (linkList == null) {
linkList = new ConcurrentLinkedDeque<>();
INSTANCE.putIfAbsent(key, linkList);
}
linkList.offer(value);
LocalCache.streamInstance();
} /**
* 队列存储,在开头添加元素
*
* @param key
* @param value
*/
@SuppressWarnings("unchecked")
@Override
public void leftPush(String key, Object value) {
ConcurrentLinkedDeque<Object> linkList = (ConcurrentLinkedDeque<Object>) INSTANCE.get(key);
if (linkList == null) {
linkList = new ConcurrentLinkedDeque<>();
INSTANCE.putIfAbsent(key, linkList);
}
linkList.offerFirst(value);
LocalCache.streamInstance();
} /**
* 删除队列的最后一个元素
*
* @param key
* @return
*/
@SuppressWarnings("unchecked")
@Override
public <T> T rightPop(String key) {
ConcurrentLinkedDeque<Object> linkList = (ConcurrentLinkedDeque<Object>) INSTANCE.get(key);
if (linkList == null) {
return null;
}
return (T) linkList.pollLast();
} /**
* 删除队列的第一个元素
*
* @param key
* @return
*/
@SuppressWarnings("unchecked")
@Override
public <T> T leftPop(String key) {
ConcurrentLinkedDeque<Object> linkList = (ConcurrentLinkedDeque<Object>) INSTANCE.get(key);
if (linkList == null) {
return null;
}
return (T) linkList.pollFirst();
} /**
*
* @param key
* @param outSecond 保存时间(秒),超出时间,被清除
* @param value
*/
@SuppressWarnings("unchecked")
@Override
public <T>T computeIfAbsent(String key, int outSecond, Function<String, Object> mappingFunction) {
T t=(T) INSTANCE.computeIfAbsent(key, mappingFunction);
KEY_TIME_INSTANCE.putIfAbsent(key,
Long.parseLong(LocalDateTime.now().plusSeconds(outSecond).format(yyyyMMddHHmmss_FMT)));
LocalCache.streamInstance();
return t;
} /**
*
* @param key
* @param value
*/
@Override
public void put(String key, Object value) {
INSTANCE.put(key, value);
} /**
*
* @param key
* @param value
* @param outSecond 保存时间(秒),超出时间,被清除
*/
@Override
public void put(String key, Object value, int outSecond) {
INSTANCE.put(key, value);
KEY_TIME_INSTANCE.put(key,
Long.parseLong(LocalDateTime.now().plusSeconds(outSecond).format(yyyyMMddHHmmss_FMT)));
LocalCache.streamInstance();
} /**
*
* @param key
* @param value
* @return
*/
@Override
public boolean putIfAbsent(String key, Object value) {
Object result = null;
result = INSTANCE.putIfAbsent(key, value);
LocalCache.streamInstance();
return result == null;
} /**
*
* @param key
* @param value
* @param outSecond 保存时间(秒),超出时间,被清除
* @return
*/
@Override
public boolean putIfAbsent(String key, Object value, int outTimeSecond) {
Object result = null;
result = INSTANCE.putIfAbsent(key, value);
KEY_TIME_INSTANCE.putIfAbsent(key,
Long.parseLong(LocalDateTime.now().plusSeconds(outTimeSecond).format(yyyyMMddHHmmss_FMT)));
LocalCache.streamInstance();
return result == null;
} /**
* 获取缓存
*
* @param key
* @return
*/
@SuppressWarnings("unchecked")
@Override
public <T> T get(String key) {
T value = (T) INSTANCE.get(key);
if (value == null) {
return null;
}
if (LocalCache.isTimeOut(key)) {
INSTANCE.remove(key);
KEY_TIME_INSTANCE.remove(key);
return null;
} else {
return value;
}
} @Override
public void expire(String key, int timeOutSecond) {
KEY_TIME_INSTANCE.put(key,
Long.parseLong(LocalDateTime.now().plusSeconds(timeOutSecond).format(yyyyMMddHHmmss_FMT)));
} /**
* 是否含有
*
* @param key
* @return
*/
@Override
public boolean hasKey(String key) {
return INSTANCE.containsKey(key);
} /**
* 删除
*
* @param id
* @return
*/
@Override
public void remove(String key) {
INSTANCE.remove(key);
} /**
* 删除并返回
*
* @param id
* @return
*/
@SuppressWarnings("unchecked")
@Override
public <T> T removeAndGet(String key) {
return (T) INSTANCE.remove(key);
} /**
* 整理缓存:<br>
* 整理的缓存的线程只能一个,节约资源开销<br>
* TRIM_INTERIM<br>
*/
private static void streamInstance() { if (TREAM_CACHE_LOCK.incrementAndGet() > 1) {
return;
}
THREAD_POOL.execute(() -> {
long now = Long.parseLong(LocalDateTime.now().format(yyyyMMddHHmmss_FMT));
do {
/*
* 1、超时缓存清除
*/
Iterator<Entry<String, Object>> instanceIt = INSTANCE.entrySet().iterator();
while (instanceIt.hasNext()) {
String key = instanceIt.next().getKey();
if (LocalCache.isTimeOut(key, now)) {
instanceIt.remove();
KEY_TIME_INSTANCE.remove(key);
}
} // /*
// * 2、 超容量,从首位开始清除
// */
// if (INSTANCE.size() > MAXCOUNT) {
// List<String> tempList = new ArrayList<>();
// for (Entry<String, Object> en : INSTANCE.entrySet()) {
// tempList.add(en.getKey());
// if (INSTANCE.size() - tempList.size() <= MAXCOUNT) {
// tempList.forEach(e -> {
// INSTANCE.remove(e);
// KEY_TIME_INSTANCE.remove(e);
// });
// break;
// }
// }
// } ThreadTool.sleep(TRIM_INTERIM);
now = Long.valueOf(LocalDateTime.now().format(yyyyMMddHHmmss_FMT));
} while (!INSTANCE.isEmpty());
TREAM_CACHE_LOCK.set(0);
});
} /**
* 判断key对比当前时间是否超时
*
* @param key
* @return
*/
private static boolean isTimeOut(String key) {
long now = Long.parseLong(LocalDateTime.now().format(yyyyMMddHHmmss_FMT));
return LocalCache.isTimeOut(key, now);
} /**
*
* 判断key对比now是否超时
*
* @param key
* @param now
* @return
*/
private static boolean isTimeOut(String key, long now) {
Long saveTime = KEY_TIME_INSTANCE.get(key);
return saveTime == null || saveTime < now;
}
}
java 手写 jvm高性能缓存的更多相关文章
- java手写多级缓存
多级缓存实现类,时间有限,该类未抽取接口,目前只支持两级缓存:JVM缓存(实现 请查看上一篇:java 手写JVM高性能缓存).redis缓存(在spring 的 redisTemplate 基础实现 ...
- 教你如何使用Java手写一个基于链表的队列
在上一篇博客[教你如何使用Java手写一个基于数组的队列]中已经介绍了队列,以及Java语言中对队列的实现,对队列不是很了解的可以我上一篇文章.那么,现在就直接进入主题吧. 这篇博客主要讲解的是如何使 ...
- Java:手写幼儿园级线程安全LRU缓存X探究影响命中率的因素
最近遇到一个需求,需要频繁访问数据库,但是访问的内容只是 id + 名称 这样的简单键值对. 频繁的访问数据库,网络上和内存上都会给数据库服务器带来不小负担. 于是打算写一个简单的LRU缓存来缓存这样 ...
- 利用Java手写简单的httpserver
前言: 在看完尚学堂JAVA300中讲解如何实现一个最简单的httpserver部分的视频之后, 一.前置知识 1.HTTP协议 当前互联网网页访问主要采用了B/S的模式,既一个浏览器,一个服务器,浏 ...
- 第三节:工厂+反射+配置文件(手写IOC)对缓存进行管理。
一. 章前小节 在前面的两个章节,我们运用依赖倒置原则,分别对 System.Web.Caching.Cache和 System.Runtime.Cacheing两类缓存进行了封装,并形成了ICach ...
- 教你如何使用Java手写一个基于数组实现的队列
一.概述 队列,又称为伫列(queue),是先进先出(FIFO, First-In-First-Out)的线性表.在具体应用中通常用链表或者数组来实现.队列只允许在后端(称为rear)进行插入操作,在 ...
- java手写线程池,完善中
package com.test001.threadpool; import java.util.LinkedList; import java.util.List; import java.util ...
- Java手写简单HashMap一(包括增加,查找,toString,泛型)
@Java 300 学习总结 HashMap底层采用实现采用了哈希表,结合了"数组和链表". 原理如图 一.定义HashMap类. 首先需要定义一个节点来存储数据,构成链表结构. ...
- java手写的动态数组JimisunArray
/** * @Author:jimisun * @Description: * @Date:Created in 22:10 2018-07-18 * @Modified By: */ public ...
随机推荐
- C# 在不同编译下的不同表现
这是我在2018年的时候发在Unity Forums上的帖子, 至今无人回复, 之前是想用TypedReference做DataTable的相关功能的, 可是结果不正确. tiancaiwrk, Oc ...
- mysql中的case when then 的用法
将立立饭饭的性别变更为女 ,烦烦 嗯嗯 问我的性别变更为男 update `table` set sex = ( case when sname in('立立','饭饭') then '女' else ...
- JS高阶---闭包面试题
[面试题1] 答案:The Window 分析: 本案例里,不存在闭包. 条件: .函数嵌套(满足) .内部函数调用外部函数变量(没有) 综上所述,该例中不存在闭包 [面试题2] 答案:My Obje ...
- c# 第一节 .net与c#区分
本节内容: 三个概念:1:.net 和c# 区分2:c# 可以做的事情3:.net 的两种交互模式 1:.net 和c# 区分 .net 一般指.Net Framework框架,是Microsoft为 ...
- springboot常见问题
什么是 Spring Boot? 为什么要用 Spring Boot? Spring Boot 的核心配置文件有哪几个?它们的区别是什么? Spring Boot 的配置文件有哪几种格式?它们有什么区 ...
- Spring Data介绍
Spring Data是Spring 的一个子项目.用于简化数据库访问,支持NoSQL和关系数据库存储.其主要目标是使数据库的访问变得方便快捷. Spring Data 项目所支持NoSQL存储: M ...
- Docker常用安装(九)
一.安装mysql 1. docker hub上面查找mysql镜像 2. 拉取镜像 #获取mysql镜像 docker pull mysql:5.6 3. 运行容器 docker run -p 1 ...
- hive数据库从文件插入数据得到结果NULL?
今天第一次接触hive这个东东,跟着教程走,当把本地文件的数据装载到新建的hive的表中时,得到的结果是NULL,如图: 也不知道为什么,初次接触,对它的这个构造还不是很熟悉,看一下建表语句: 解决: ...
- 了解html标签
<title></title> 1.网页标题 2.当我们收藏网页时,默认标题就是网页标题 3.seo(搜索引擎优化) <h1></h1>~<h6& ...
- koa2+mysql+vue实现用户注册、登录、token验证
说明: node.js提供接口,vue展现页面,前后端分离,出于编辑器功能和编辑习惯,vue用HbuilderX,node.js用VScode.(PS:仅作为学习笔记,如有不当之处欢迎指出,在此先谢为 ...