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(); } } }