zoukankan      html  css  js  c++  java
  • ConcurrentHashMap 实现缓存类

    参考:https://blog.csdn.net/woshilijiuyi/article/details/81335497

    在规定时间内,使用 hashMap 实现一个缓存工具类,需要考虑一下几点

    1. 不可变对象
    2. 单例
    3. 线程安全
    4. 回收失效数据
    5. 垃圾回收
    6. 缓存大小
    7. LRU

    注备:

    • LRU: Least Recently Used ,即最近最少使用,是一种常用的页面置换算法,选择最近最久未使用的页面淘汰。
    • OPT :  最佳置换算法,是一种理想情况下的置换算法,但实际上不可实现。思想是标记每个页面多久后被使用,最大的将被淘汰
    • FIFO:先进先出,建立一个FIFO 队列,收容所有在内存中的页,被置换的页总在队列头上进行。
    • LFU : 最少使用置换算法,使用最少使用置换算法在内存中的每个页面设置一个移位寄存器,记录页面被使用的频率。
    package com;
    
    import lombok.Data;
    import java.util.LinkedList;
    import java.util.Map;
    import java.util.concurrent.ConcurrentHashMap;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantReadWriteLock;
    
    /**
     * Created by baizhuang on 2019/11/15 10:34.
     */
    
    public class CacheManager {
    
        private CacheManager() {
        }
    
        //是否开启清除失效缓存
        private volatile Boolean clearExpireCacheEnable = true;
    
        //缓存失效时间
        private long cacheTimeout = 12 * 60 * 60 * 1000L;
    
        //缓存使用记录
        private static LinkedList<Object> cacheUseRecord = new LinkedList<>();
    
        //可缓存最大数量
        private static Integer MAX_CACHE_SIZE = 80;
    
        //重入读写锁
        private static ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
        private static Lock writeLock = reentrantReadWriteLock.writeLock();
        private static Lock readLock = reentrantReadWriteLock.readLock();
    
        private final static Map<Object, CacheEntry> cacheEntryMap = new ConcurrentHashMap<>();
    
    
        private void init() {
            initClearTask();
        }
    
        //自定义缓存失效时间
        private void init(long cacheTimes) {
            this.cacheTimeout = cacheTimes;
            initClearTask();
        }
    
        private void initClearTask() {
            //启动清除失效缓存数据
            if (clearExpireCacheEnable) {
                new ClearCacheTask().start();
            }
        }
    
    
        private static CacheManager getCacheManagerInstance() {
            return CacheManagerFactory.CACHE_MANAGER;
        }
    
        private static class CacheManagerFactory {
            private static final CacheManager CACHE_MANAGER = new CacheManager();
        }
    
        private class ClearCacheTask extends Thread {
    
            ClearCacheTask() {
                super.setName("clear cache task start ...");
            }
    
            @Override
            public void run() {
                while (clearExpireCacheEnable) {
                    try {
                        long now = System.currentTimeMillis();
    
                        //定时清理
                        try {
    //                        Thread.sleep(1000 * 60 * 60);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
    
                        cacheEntryMap.keySet().stream().forEach(key -> {
                            try {
                                writeLock.lock();
    
                                //判断使用记录中的key是否已经被LRU清除
                                if (!cacheUseRecord.contains(key)) {
                                    return;
                                }
    
                                CacheEntry entry = cacheEntryMap.get(key);
                                if (now - entry.lastTouchTime >= cacheTimeout) {
                                    cacheEntryMap.remove(key);
                                    cacheUseRecord.remove(key);
                                    System.out.println("清理缓存key:" + key);
    
                                }
                            } finally {
                                writeLock.unlock();
                            }
                        });
    
                        Thread.sleep(cacheTimeout);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    
    
        //失效时间,value,entry,可根据需要决定是否继承Map.Entry<K,V>
        @Data
        private class CacheEntry {
            long lastTouchTime;
    
            Object value;
    
            CacheEntry(Object value) {
                super();
                this.value = value;
                this.lastTouchTime = System.currentTimeMillis();
            }
        }
    
    
        public Object get(Object key) {
    
            readLock.lock();
            CacheEntry entry = null;
            try {
                entry = cacheEntryMap.get(key);
            } finally {
                readLock.unlock();
            }
            if (null == entry)
                return null;
    
            //更新缓存访问时间
            touchCache(entry);
            //更新使用记录
            touchUseRecord(key);
    
            return entry == null ? null : entry.value;
        }
    
        //更新缓存访问时间
        public static void touchCache(CacheEntry entry) {
            writeLock.lock();
            try {
                entry.setLastTouchTime(System.currentTimeMillis());
            } finally {
                writeLock.unlock();
            }
    
        }
    
        //更新缓存使用记录
        public static void touchUseRecord(Object key) {
    
            writeLock.lock();
            try {
                //删除使用记录
                cacheUseRecord.remove(key);
                //新增使用记录到首位
                cacheUseRecord.add(0, key);
            } finally {
                writeLock.unlock();
            }
        }
    
    
        public Object put(Object key, Object value) throws Exception {
    
            //判断缓存大小是否够用,否则根据LRU删除最久未使用的元素
            if (cacheEntryMap.size() > MAX_CACHE_SIZE) {
                deleteLRU();
            }
            if (cacheEntryMap.size() > MAX_CACHE_SIZE) {
                throw new Exception("缓存大小超出限制");
            }
    
            CacheEntry entry = new CacheEntry(value);
    
            writeLock.lock();
            try {
                cacheEntryMap.put(key, entry);
                cacheUseRecord.add(0, key);
            } finally {
                writeLock.unlock();
            }
            return value;
        }
    
    
        /**
         * 删除最近最久未使用的缓存
         */
        public static void deleteLRU() {
    
            Object cacheKey = null;
            writeLock.lock();
            try {
                cacheKey = cacheUseRecord.remove(cacheUseRecord.size() - 1);
                cacheEntryMap.remove(cacheKey);
                System.out.println("LRU清除元素key:" + cacheKey);
            } finally {
                writeLock.unlock();
            }
        }
    
        public static void delete(Object key) {
    
            if (null == key)
                return;
    
            writeLock.lock();
            try {
                cacheEntryMap.remove(key);
                cacheUseRecord.remove(key);
            } finally {
                writeLock.unlock();
            }
        }
    
    
        public static void clear() {
    
            writeLock.lock();
            try {
                cacheEntryMap.clear();
                cacheUseRecord.clear();
            } finally {
                writeLock.unlock();
            }
        }
    
    
        public static void main(String[] args) throws Exception {
            CacheManager cacheManager = CacheManager.getCacheManagerInstance();
            cacheManager.init(0);
    
            for (int i = 0; i < 200; i++) {
                cacheManager.put(i + "", i);
            }
        }
    }
  • 相关阅读:
    寒假要学习的知识点
    Linux firewall防火墙 换成 iptables 防火墙
    git add出现 "fatal: in unpopulated submodule XXX" 错误
    使用navicat连接mysql报10038错时解决方法
    php 获取url重定向
    php 获取文件后缀的几种方法
    Windows+PHP7.3环境下安装imagick扩展和imagemagick
    php7 连接数据库的方法
    Warning from https://mirrors.aliyun.com/composer: Support for Composer 1 is deprecated and some packages will not be available. You should upgrade to Composer 2.
    php 执行GuzzleHttp请求时发生cURL error 60: SSL certificate problem错误的解决方法
  • 原文地址:https://www.cnblogs.com/baizhuang/p/11865261.html
Copyright © 2011-2022 走看看