Java | ConcurrentHashMap 实现缓存类(阿里面试题)

概述

之前参与过阿里的一次面试,机试,在规定的时间内,用hashMap实现一个缓存工具类。题目比较开放,主要考虑到以下几点:

  • 不可变对象
  • 单例
  • 线程安全
  • 回收失效数据
  • 垃圾回收
/**
 * Created by zhangshukang on 2018/8/1.
 */
public class CacheManager {

    private CacheManager() {
    }

    //是否开启清除失效缓存
    private volatile Boolean clearExpireCacheEnable = true;

    //缓存失效时间
    private long cacheTimeout = 12 * 60 * 60 * 1000L;

    //重入读写锁
    private ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
    private Lock writeLock = reentrantReadWriteLock.writeLock();
    private Lock readLock = reentrantReadWriteLock.readLock();

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

    //失效时间,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();
        }
    }


    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 (InterruptedException e) {
                        e.printStackTrace();
                    }

                    cacheEntryMap.keySet().stream().forEach(key -> {
                        CacheEntry entry = cacheEntryMap.get(key);
                        if (now - entry.lastTouchTime >= cacheTimeout) {
                            synchronized (cacheEntryMap) {
                                cacheEntryMap.remove(key);
                                System.out.println("清理缓存key:" + key);
                            }
                        }
                    });

                    Thread.sleep(cacheTimeout);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }


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

        return entry == null ? null : entry.value;
    }

    public void touchCache(CacheEntry entry) {
        writeLock.lock();
        try {
            entry.setLastTouchTime(System.currentTimeMillis());
        } finally {
            writeLock.unlock();
        }

    }

    public Object put(Object key, Object value) {
        CacheEntry entry = new CacheEntry(value);

        writeLock.lock();
        try {
            cacheEntryMap.put(key, entry);
        } finally {
            writeLock.unlock();
        }
        return value;
    }

    public void clear() {

        writeLock.lock();
        try {
            cacheEntryMap.clear();
        } finally {
            writeLock.unlock();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        CacheManager cacheManager = CacheManager.getCacheManagerInstance();
        cacheManager.init();
        cacheManager.put("test", "admin");
        Thread.sleep(5000l);
        System.out.println(cacheManager.get("test"));
    }
}

猜你喜欢

转载自blog.csdn.net/woshilijiuyi/article/details/81335497