cache缓存简单实现

思路:LinkedList + HashMap: LinkedList用来保存key的访问情况,最近访问的key将会放置到链表的最尾端,如果链表大小超过容量,移除链表的第一个节点,同时移除该key在hashmap中对应的键值对。程序如下:

class LRUCache {
private HashMap<Integer, Integer> hashMap = null;
private LinkedList list = null;
private int capacity;
public LRUCache(int capacity) {
hashMap = new HashMap<>(capacity);
list = new LinkedList();
this.capacity = capacity;
}

public int get(int key) {
    if(hashMap.containsKey(key)){
        list.remove((Object)key);
        list.addLast(key);
        return hashMap.get(key);
    }
    return  -1;
}

public void put(int key, int value) {
    if(list.contains((Integer)key)){
        list.remove((Integer)key);
        list.addLast((Integer)key);
        hashMap.put(key, value);
        return;
    }
    if(list.size() == capacity){
        Integer v = list.get(0);
        list.remove(0);
        hashMap.remove((Object)v);
    }
    list.addLast(key);
    hashMap.put(key, value);
}

}
(2)多线程并发版LRU Cache
 与单线程思路类似,将HashMap和LinkedList换成支持线程安全的容器ConcurrentHashMap和ConcurrentLinkedQueue结构。ConcurrentLinkedQueue是一个基于链表,支持先进先出的的队列结构,处理方法同单线程类似,只不过为了保证多线程下的安全问题,我们会使用支持读写分离锁的ReadWiterLock来保证线程安全。它可以实现:

1.同一时刻,多个线程同时读取共享资源。

2.同一时刻,只允许单个线程进行写操作。

/*

  • 泛型中通配符

  • ? 表示不确定的 java 类型

  • T (type) 表示具体的一个java类型

  • K V (key value) 分别代表java键值中的Key Value

  • E (element) 代表Element
    /
    public class MyLRUCache<K, V> {
    private final int capacity;
    private ConcurrentHashMap<K, V> cacheMap;
    private ConcurrentLinkedQueue keys;
    ReadWriteLock RWLock = new ReentrantReadWriteLock();
    /

    • 读写锁
      */
      private Lock readLock = RWLock.readLock();
      private Lock writeLock = RWLock.writeLock();

    private ScheduledExecutorService scheduledExecutorService;

    public MyLRUCache(int capacity) {
    this.capacity = capacity;
    cacheMap = new ConcurrentHashMap<>(capacity);
    keys = new ConcurrentLinkedQueue<>();
    scheduledExecutorService = Executors.newScheduledThreadPool(10);
    }

    public boolean put(K key, V value, long expireTime){
    writeLock.lock();
    try {
    //需要注意containsKey和contains方法方法的区别
    if(cacheMap.containsKey(key)){
    keys.remove(key);
    keys.add(key);
    cacheMap.put(key, value);
    return true;
    }
    if(cacheMap.size() == capacity){
    K tmp = keys.poll();
    if( key != null){
    cacheMap.remove(tmp);
    }
    }
    cacheMap.put(key, value);
    keys.add(key);
    if(expireTime > 0){
    removeAfterExpireTime(key, expireTime);
    }
    return true;
    }finally {
    writeLock.unlock();
    }
    }

    public V get(K key){
    readLock.lock();
    try {
    if(cacheMap.containsKey(key)){
    keys.remove(key);
    keys.add(key);
    return cacheMap.get(key);
    }
    return null;
    }finally {
    readLock.unlock();
    }
    }

    public boolean remove(K key){
    writeLock.lock();
    try {
    if(cacheMap.containsKey(key)){
    cacheMap.remove(key);
    keys.remove(key);
    return true;
    }
    return false;
    }finally {
    writeLock.unlock();
    }
    }

    private void removeAfterExpireTime(K key, long expireTime){
    scheduledExecutorService.schedule(new Runnable() {
    @Override
    public void run() {
    cacheMap.remove(key);
    keys.remove(key);
    }
    }, expireTime, TimeUnit.MILLISECONDS);
    }
    public int size(){
    return cacheMap.size();
    }
    }
      在代码中添加了设置键值对失效的put方法,通过使用一个定时器线程池保证过期键值对的及时清理。测试代码如下:

public class LRUTest {
public static void main(String[] args) throws InterruptedException {
/*
MyLRUCache<String, Integer> myLruCache = new MyLRUCache(100000);
ExecutorService es = Executors.newFixedThreadPool(10);
AtomicInteger atomicInteger = new AtomicInteger(1);
CountDownLatch latch = new CountDownLatch(10);
long starttime = System.currentTimeMillis();
for (int i = 0; i < 10; i++) {
es.submit(new Runnable() {
@Override
public void run() {
for (int j = 0; j < 100000; j++) {
int v = atomicInteger.getAndIncrement();
myLruCache.put(Thread.currentThread().getName() + “_” + v, v, 200000);
}
latch.countDown();
}
});
}

    latch.await();
    long endtime = System.currentTimeMillis();
    es.shutdown();
    System.out.println("Cache size:" + myLruCache.size()); //Cache size:1000000
    System.out.println("Time cost: " + (endtime - starttime));
  */
    MyLRUCache<Integer, String> myLruCache = new MyLRUCache<>( 10);
    myLruCache.put(1, "Java", 1000);
    myLruCache.put(2, "C++", 2000);
    myLruCache.put(3, "Java", 3000);
    System.out.println(myLruCache.size());//3
    Thread.sleep(2200);
    System.out.println(myLruCache.size());//1
}

}
深圳网站建设www.sz886.com

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值