如何用Java案例实现内存缓存?

wen java案例 9

本文目录导读:

如何用Java案例实现内存缓存?

  1. 基础版本 - 简单HashMap缓存
  2. 带过期时间的缓存
  3. 完整的内存缓存实现 - 支持最大容量和LRU淘汰
  4. 使用示例
  5. 带统计功能的缓存

我来通过一个简单但完整的Java案例,展示如何实现内存缓存。

基础版本 - 简单HashMap缓存

import java.util.concurrent.ConcurrentHashMap;
public class SimpleCache<K, V> {
    private final ConcurrentHashMap<K, V> cache = new ConcurrentHashMap<>();
    public void put(K key, V value) {
        cache.put(key, value);
    }
    public V get(K key) {
        return cache.get(key);
    }
    public void remove(K key) {
        cache.remove(key);
    }
    public void clear() {
        cache.clear();
    }
    public boolean containsKey(K key) {
        return cache.containsKey(key);
    }
    public int size() {
        return cache.size();
    }
}

带过期时间的缓存

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
public class ExpiringCache<K, V> {
    private static class CacheEntry<V> {
        private final V value;
        private final long expirationTime;
        private final long createdTime;
        public CacheEntry(V value, long ttlMillis) {
            this.value = value;
            this.createdTime = System.currentTimeMillis();
            this.expirationTime = createdTime + ttlMillis;
        }
        public boolean isExpired() {
            return System.currentTimeMillis() > expirationTime;
        }
        public V getValue() {
            return value;
        }
        public long getRemainingTime() {
            long remaining = expirationTime - System.currentTimeMillis();
            return Math.max(0, remaining);
        }
    }
    private final ConcurrentHashMap<K, CacheEntry<V>> cache = new ConcurrentHashMap<>();
    private final long defaultTtlMillis;
    public ExpiringCache(long defaultTtlMillis) {
        this.defaultTtlMillis = defaultTtlMillis;
    }
    public ExpiringCache(long ttl, TimeUnit unit) {
        this.defaultTtlMillis = unit.toMillis(ttl);
    }
    public void put(K key, V value) {
        put(key, value, defaultTtlMillis);
    }
    public void put(K key, V value, long ttlMillis) {
        cache.put(key, new CacheEntry<>(value, ttlMillis));
    }
    public V get(K key) {
        CacheEntry<V> entry = cache.get(key);
        if (entry == null) {
            return null;
        }
        if (entry.isExpired()) {
            cache.remove(key);
            return null;
        }
        return entry.getValue();
    }
    public void remove(K key) {
        cache.remove(key);
    }
    public void clear() {
        cache.clear();
    }
    public int size() {
        // 清理过期条目后再返回大小
        removeExpiredEntries();
        return cache.size();
    }
    private void removeExpiredEntries() {
        cache.entrySet().removeIf(entry -> entry.getValue().isExpired());
    }
}

完整的内存缓存实现 - 支持最大容量和LRU淘汰

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class MemoryCache<K, V> {
    private static class CacheEntry<V> {
        private final V value;
        private final long expirationTime;
        public CacheEntry(V value, long expirationTime) {
            this.value = value;
            this.expirationTime = expirationTime;
        }
        public boolean isExpired() {
            return System.currentTimeMillis() > expirationTime;
        }
    }
    private final int maxSize;
    private final long defaultTtlMillis;
    private final LinkedHashMap<K, CacheEntry<V>> cache;
    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    public MemoryCache(int maxSize, long defaultTtlMillis) {
        this.maxSize = maxSize;
        this.defaultTtlMillis = defaultTtlMillis;
        // 使用LinkedHashMap实现LRU淘汰
        this.cache = new LinkedHashMap<K, CacheEntry<V>>(16, 0.75f, true) {
            @Override
            protected boolean removeEldestEntry(Map.Entry<K, CacheEntry<V>> eldest) {
                return size() > MemoryCache.this.maxSize;
            }
        };
    }
    public void put(K key, V value) {
        put(key, value, defaultTtlMillis);
    }
    public void put(K key, V value, long ttlMillis) {
        long expirationTime = System.currentTimeMillis() + ttlMillis;
        CacheEntry<V> entry = new CacheEntry<>(value, expirationTime);
        lock.writeLock().lock();
        try {
            cache.put(key, entry);
            System.out.println("缓存添加成功 - Key: " + key + ", TTL: " + ttlMillis + "ms");
        } finally {
            lock.writeLock().unlock();
        }
    }
    public V get(K key) {
        lock.readLock().lock();
        try {
            CacheEntry<V> entry = cache.get(key);
            if (entry == null) {
                return null;
            }
            if (entry.isExpired()) {
                lock.readLock().unlock();
                lock.writeLock().lock();
                try {
                    cache.remove(key);
                    System.out.println("缓存已过期 - Key: " + key);
                    return null;
                } finally {
                    lock.writeLock().unlock();
                    lock.readLock().lock();
                }
            }
            return entry.value;
        } finally {
            lock.readLock().unlock();
        }
    }
    public void remove(K key) {
        lock.writeLock().lock();
        try {
            cache.remove(key);
            System.out.println("缓存已删除 - Key: " + key);
        } finally {
            lock.writeLock().unlock();
        }
    }
    public void clear() {
        lock.writeLock().lock();
        try {
            cache.clear();
            System.out.println("缓存已清空");
        } finally {
            lock.writeLock().unlock();
        }
    }
    public int size() {
        lock.readLock().lock();
        try {
            return cache.size();
        } finally {
            lock.readLock().unlock();
        }
    }
    public void cleanExpiredEntries() {
        lock.writeLock().lock();
        try {
            cache.entrySet().removeIf(entry -> entry.getValue().isExpired());
            System.out.println("过期缓存清理完成");
        } finally {
            lock.writeLock().unlock();
        }
    }
    public Map<K, V> getAll() {
        lock.readLock().lock();
        try {
            Map<K, V> result = new java.util.HashMap<>();
            for (Map.Entry<K, CacheEntry<V>> entry : cache.entrySet()) {
                if (!entry.getValue().isExpired()) {
                    result.put(entry.getKey(), entry.getValue().value);
                }
            }
            return result;
        } finally {
            lock.readLock().unlock();
        }
    }
}

使用示例

import java.util.concurrent.TimeUnit;
public class CacheExample {
    public static void main(String[] args) throws InterruptedException {
        // 创建缓存:最大容量100,默认过期时间5秒
        MemoryCache<String, String> cache = new MemoryCache<>(100, 5000);
        // 1. 基本使用
        System.out.println("=== 基本使用 ===");
        cache.put("user1", "张三");
        cache.put("user2", "李四");
        System.out.println("获取user1: " + cache.get("user1")); // 输出: 张三
        System.out.println("缓存大小: " + cache.size()); // 输出: 2
        // 2. 过期测试
        System.out.println("\n=== 过期测试 ===");
        cache.put("temp", "临时数据", 2000); // 2秒过期
        System.out.println("立即获取: " + cache.get("temp")); // 输出: 临时数据
        Thread.sleep(3000); // 等待3秒
        System.out.println("3秒后获取: " + cache.get("temp")); // 输出: null(已过期)
        // 3. 自定义过期时间
        System.out.println("\n=== 自定义过期时间 ===");
        cache.put("session1", "session数据", 10000); // 10秒过期
        cache.put("config", "配置信息", TimeUnit.MINUTES.toMillis(30)); // 30分钟过期
        // 4. 删除和清空
        System.out.println("\n=== 删除操作 ===");
        cache.put("delete_test", "将被删除");
        cache.remove("delete_test");
        System.out.println("删除后获取: " + cache.get("delete_test")); // 输出: null
        // 5. 模拟LRU淘汰
        System.out.println("\n=== LRU淘汰测试 ===");
        MemoryCache<Integer, String> smallCache = new MemoryCache<>(3, 60000);
        smallCache.put(1, "A");
        smallCache.put(2, "B");
        smallCache.put(3, "C");
        smallCache.get(1); // 访问key 1
        smallCache.get(2); // 访问key 2
        smallCache.put(4, "D"); // 添加新元素,最久未使用的key 3将被淘汰
        System.out.println("获取key 1: " + smallCache.get(1)); // 输出: A
        System.out.println("获取key 3: " + smallCache.get(3)); // 输出: null(被淘汰)
        System.out.println("缓存大小: " + smallCache.size()); // 输出: 3
        // 6. 批量清理过期缓存
        System.out.println("\n=== 清理过期缓存 ===");
        cache.cleanExpiredEntries();
        // 7. 获取所有有效缓存
        System.out.println("\n所有有效缓存: ");
        cache.getAll().forEach((key, value) -> 
            System.out.println(key + " -> " + value));
        // 8. 清空缓存
        cache.clear();
        System.out.println("\n清空后大小: " + cache.size()); // 输出: 0
    }
}

带统计功能的缓存

public class StatisticsCache<K, V> extends MemoryCache<K, V> {
    private long hitCount = 0;
    private long missCount = 0;
    private long totalPuts = 0;
    public StatisticsCache(int maxSize, long defaultTtlMillis) {
        super(maxSize, defaultTtlMillis);
    }
    @Override
    public V get(K key) {
        V value = super.get(key);
        if (value != null) {
            hitCount++;
        } else {
            missCount++;
        }
        return value;
    }
    @Override
    public void put(K key, V value, long ttlMillis) {
        super.put(key, value, ttlMillis);
        totalPuts++;
    }
    public void printStatistics() {
        System.out.println("=== 缓存统计 ===");
        System.out.println("总存储次数: " + totalPuts);
        System.out.println("命中次数: " + hitCount);
        System.out.println("未命中次数: " + missCount);
        System.out.println("命中率: " + 
            String.format("%.2f", (double) hitCount / (hitCount + missCount) * 100) + "%");
        System.out.println("当前大小: " + size());
    }
}

这个案例展示了内存缓存的完整实现,包括:

  1. 基本功能:存储、获取、删除
  2. 过期策略:支持TTL(生存时间)
  3. 淘汰策略:LRU(最近最少使用)
  4. 线程安全:使用读写锁保证并发安全
  5. 性能优化:使用ConcurrentHashMap
  6. 统计功能:命中率等性能监控

你可以根据实际需求选择合适的实现方案。

抱歉,评论功能暂时关闭!