并发编程中的ConcurrentHashMap
2023-12-15 23:18:20
对于ConcurrentHashMap相信大家很多的应用中都有用到,它的一些详细介绍各大博主都已经讲的详细的不能再详细了,接下来我们主要看下他的一些实现方法。
下面这个是我的应用中用到的,大家可以借鉴操作(可以做到即办即用)
目录
ConcurrentHashMap是Java中并发编程中常用的一种线程安全的哈希表,它是对Hashtable的替代方案,相比于Hashtable能够更好地支持并发访问。
CSDN给的优缺点
优点:
- 线程安全:ConcurrentHashMap中的所有方法都是线程安全的;
- 高效性:ConcurrentHashMap使用分段锁技术,可以有效地缩小锁的范围,提高了并发访问的性能;
- 支持高并发:ConcurrentHashMap中每个Segment都相互独立,因此可以支持更高的并发量;
缺点:
- 内存占用:ConcurrentHashMap的分段锁机制增加了内存的占用;
- 不支持键值为null:ConcurrentHashMap的键值不支持为null,如果需要使用null,可以使用ConcurrentSkipListMap。
使用场景:
- 多线程并发访问:ConcurrentHashMap适用于多线程并发访问的场景;
- 高并发量:ConcurrentHashMap适用于需要支持高并发量的场景;
- 缓存:ConcurrentHashMap可以用于实现缓存,可以将缓存数据存储在其中。
对应方法
1、设置缓存
2、获取缓存
3、删除所有缓存
4、删除单个缓存
5、判断缓存在不在,过没过期
6、删除最近最久未使用的缓存
7、删除过期的缓存
8、检查大小
9、保存缓存的使用记录
10、设置清理线程的运行状态为正在运行
11、开启清理过期缓存的线程
import lombok.Data;
import java.io.Serializable;
/**
* 缓存
*/
@Data
public class CacheObj implements Serializable {
private static final long serialVersionUID = 5272376851165037333L;
/**
* 缓存对象
*/
private Object cacheValue;
/**
* 缓存过期时间
*/
private Long ttlTime;
public CacheObj(Object cacheValue, Long ttlTime) {
this.cacheValue = cacheValue;
this.ttlTime = ttlTime;
}
@Override
public String toString() {
return "CacheObj {" +
"cacheValue = " + cacheValue +
", ttlTime = " + ttlTime +
'}';
}
}
import lombok.extern.slf4j.Slf4j;
/**
* 每一分钟清理一次过期缓存
*/
@Slf4j
public class CleanTimeOutThread implements Runnable {
@Override
public void run() {
ConcurrentHashMapCacheUtil.setCleanThreadRun();
while (true) {
log.warn("clean thread run ");
ConcurrentHashMapCacheUtil.deleteTimeOut();
try {
Thread.sleep(ConcurrentHashMapCacheUtil.ONE_MINUTE);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 本地缓存
*/
@Slf4j
@Component
public class ConcurrentHashMapCacheUtil {
/**
* 缓存最大个数
*/
private static final Integer CACHE_MAX_NUMBER = 50000;
/**
* 当前缓存个数
*/
private static Integer CURRENT_SIZE = 0;
/**
* 时间一分钟
*/
static final Long ONE_MINUTE = 60 * 1000L;
/**
* 永不过期
*/
private static final Long CACHE_FOREVER = -1L;
/**
* 缓存对象
*/
private static final Map<String, CacheObj> CACHE_OBJECT_MAP = new ConcurrentHashMap();
/**
* 这个记录了缓存使用的最后一次的记录,最近使用的在最前面
*/
private static final List<String> CACHE_USE_LOG_LIST = new LinkedList();
/**
* 清理过期缓存是否在运行
*/
private static volatile Boolean CLEAN_THREAD_IS_RUN = false;
/**
* 设置缓存
*
* @param cacheKey
* @param cacheValue
* @param cacheTime
*/
public static void setCache(String cacheKey, Object cacheValue, long cacheTime) {
Long ttlTime = null;
if (cacheTime <= 0L) {
if (cacheTime == -1L) {
ttlTime = -1L;
} else {
return;
}
}
// checkSize();
// saveCacheUseLog(cacheKey);
CURRENT_SIZE = CURRENT_SIZE + 1;
if (ttlTime == null) {
ttlTime = System.currentTimeMillis() + cacheTime;
}
CacheObj cacheObj = new CacheObj(cacheValue, ttlTime);
CACHE_OBJECT_MAP.put(cacheKey, cacheObj);
log.info("have set key :{}", cacheKey);
}
/**
* 设置缓存
*
* @param cacheKey
* @param cacheValue
*/
public static void setCache(String cacheKey, Object cacheValue) {
setCache(cacheKey, cacheValue, CACHE_FOREVER);
}
/**
* 获取缓存
*
* @param cacheKey
* @return
*/
public static Object getCache(String cacheKey) {
// startCleanThread();
if (checkCache(cacheKey)) {
saveCacheUseLog(cacheKey);
return CACHE_OBJECT_MAP.get(cacheKey).getCacheValue();
}
return null;
}
public static boolean isExist(String cacheKey) {
return checkCache(cacheKey);
}
/**
* 删除所有缓存
*/
public static void clear() {
log.info("have clean all key !");
CACHE_OBJECT_MAP.clear();
CURRENT_SIZE = 0;
}
/**
* 删除单个缓存
*
* @param cacheKey
*/
public static void deleteCache(String cacheKey) {
Object cacheValue = CACHE_OBJECT_MAP.remove(cacheKey);
if (cacheValue != null) {
log.info("have delete key : {}", cacheKey);
CURRENT_SIZE = CURRENT_SIZE - 1;
}
}
/**
* 判断缓存在不在,过没过期
*
* @param cacheKey
* @return
*/
private static boolean checkCache(String cacheKey) {
CacheObj cacheObj = CACHE_OBJECT_MAP.get(cacheKey);
if (cacheObj == null) {
return false;
}
if (cacheObj.getTtlTime() == -1L) {
return true;
}
if (cacheObj.getTtlTime() < System.currentTimeMillis()) {
deleteCache(cacheKey);
return false;
}
return true;
}
/**
* 删除最近最久未使用的缓存
*/
private static void deleteLRU() {
log.info("delete Least recently used run!");
String cacheKey = null;
synchronized (CACHE_USE_LOG_LIST) {
if (CACHE_USE_LOG_LIST.size() >= CACHE_MAX_NUMBER - 10) {
cacheKey = CACHE_USE_LOG_LIST.remove(CACHE_USE_LOG_LIST.size() - 1);
}
}
if (cacheKey != null) {
deleteCache(cacheKey);
}
}
/**
* 删除过期的缓存
*/
public static void deleteTimeOut() {
log.info("delete time out run!");
List<String> deleteKeyList = new LinkedList<>();
for (Map.Entry<String, CacheObj> entry : CACHE_OBJECT_MAP.entrySet()) {
if (entry.getValue().getTtlTime() < System.currentTimeMillis() && entry.getValue().getTtlTime() != -1L) {
deleteKeyList.add(entry.getKey());
}
}
for (String deleteKey : deleteKeyList) {
deleteCache(deleteKey);
}
log.info("delete cache count is :{}", deleteKeyList.size());
}
/**
* 检查大小
* 当当前大小如果已经达到最大大小
* 首先删除过期缓存,如果过期缓存删除过后还是达到最大缓存数目
* 删除最久未使用缓存
*/
private static void checkSize() {
if (CURRENT_SIZE >= CACHE_MAX_NUMBER) {
deleteTimeOut();
}
if (CURRENT_SIZE >= CACHE_MAX_NUMBER) {
deleteLRU();
}
}
/**
* 保存缓存的使用记录
*
* @param cacheKey
*/
private static synchronized void saveCacheUseLog(String cacheKey) {
synchronized (CACHE_USE_LOG_LIST) {
CACHE_USE_LOG_LIST.remove(cacheKey);
CACHE_USE_LOG_LIST.add(0, cacheKey);
}
}
/**
* 设置清理线程的运行状态为正在运行
*/
public static void setCleanThreadRun() {
CLEAN_THREAD_IS_RUN = true;
}
/**
* 开启清理过期缓存的线程
*/
private static void startCleanThread() {
if (!CLEAN_THREAD_IS_RUN) {
CleanTimeOutThread cleanTimeOutThread = new CleanTimeOutThread();
Thread thread = new Thread(cleanTimeOutThread);
//设置为后台守护线程
thread.setDaemon(true);
thread.start();
}
}
}
文章来源:https://blog.csdn.net/weixin_59383491/article/details/134953726
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!