JAVA中WeakHashMap的应用场景

举报
山河已无恙 发表于 2021/12/03 21:53:50 2021/12/03
【摘要】 可以使用WeakhashMap实现一个线程安全的基于LRU本地缓存

 WeakHashMap是啥:

WeakHashMap和HashMap都是通过"拉链法"实现的散列表。它们的源码绝大部分内容都一样,这里就只是对它们不同的部分就是说明。

 WeakReference是“弱键”实现的哈希表。它这个“弱键”的目的就是:实现对“键值对”的动态回收。当“弱键”不再被使用到时,GC会回收它,WeakReference也会将“弱键”对应的键值对删除。


 “弱键”是一个“弱引用(WeakReference)”,在Java中,WeakReference和ReferenceQueue 是联合使用的。在WeakHashMap中亦是如此:如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。 接着,WeakHashMap会根据“引用队列”,来删除“WeakHashMap中已被GC回收的‘弱键’对应的键值对”。

实际的应用:

可以使用WeakhashMap实现一个线程安全的基于LRU本地缓存

在Tomcat的工具类里,有这样一种实现。基于LRU策略,很巧妙。

Github :https://github.com/apache/tomcat/blob/3e5ce3108e2684bc25013d9a84a7966a6dcd6e14/java/org/apache/tomcat/util/collections/ConcurrentCache.java

WeakHashMap 

package com.liruilong.common.util.concurrentcache;

import java.util.Map;
import java.util.Objects;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;

/**
 * <per>
 * <a>https://github.com/apache/tomcat/blob/3e5ce3108e2684bc25013d9a84a7966a6dcd6e14/java/org/apache/tomcat/util/collections/ConcurrentCache.java<a/>
 * <per/>
 * @Author  https://github.com/apache/tomcat/blob/3e5ce3108e2684bc25013d9a84a7966a6dcd6e14/java/org/apache/tomcat/util/collections/ConcurrentCache.java
 * @Date 2020/8/11 08:46
 * @Description: org.apache.tomcat.util.collections;工具类,
 * <p>基于WeakHashMap 实现线程安全的缓存</p>
 */
public final class ConcurrentCache<K,V> {

    private final int size;

    private final  Map<K,V> eden;

    private final Map<K,V> longterm;

    public  ConcurrentCache(int size){
        this.size = size;
        this.eden = new ConcurrentHashMap<>(size);
        this.longterm = new WeakHashMap<>(size);
    }

    public V get(K k){
        V v = this.eden.get(k);
        if (Objects.isNull(v)){
                synchronized (longterm){
                    v = this.longterm.get(k);
                }
                if (Objects.nonNull(v)){
                    this.eden.put(k,v);
                }
        }
        return v;
    }
    public void put(K k,V v){
        if (this.eden.size() >= size){
            synchronized (longterm){
                this.longterm.putAll(this.eden);
            }
            this.eden.clear();
        }
        this.eden.put(k,v);
    }



}

在原有基础上,我做了改进,使用 volatile 和静态工厂的方式实现,只是个人想法,不足之处请小伙伴指出来。

package com.liruilong.common.util.concurrentcache;

import java.util.Map;
import java.util.Objects;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Author Liruilong
 * @Date 2020/8/11 09:37
 * @Description: 基于 WeakHashMap 的缓存实现
 */
public class WeakHashMapCache<K,V> {
    private final int size;

    private final Map<K,V> eden;

    private final Map<K,V> longterm;

    private WeakHashMapCache(Builder<K,V> builder){
       this.size = builder.size;
       this.eden = builder.eden;
       this.longterm = builder.longterm;
    }

    public  static class Builder<K,V>{
        private volatile int size;

        private volatile  Map<K,V> eden;

        private volatile Map<K,V> longterm;

        public  Builder(int size){
            this.size = rangeCheck(size,Integer.MAX_VALUE,"缓存容器初始化容量异常");
            this.eden = new ConcurrentHashMap<>(size);
            this.longterm = new WeakHashMap<>(size);
        }

        private static int rangeCheck(int val, int i, String arg) {
            if (val < 0 || val > i) {
                throw new IllegalArgumentException(arg + ":" + val);
            }
            return  val;
        }
        public WeakHashMapCache build(){
            return new WeakHashMapCache(this);
        }

    }
    public V get(K k){
        V v = this.eden.get(k);
        if (Objects.isNull(v)){
            v = this.longterm.get(k);
            if (Objects.nonNull(v)){
                this.eden.put(k,v);
            }
        }
        return v;
    }
    public void put(K k,V v){
        if (this.eden.size() >= size){
            this.longterm.putAll(this.eden);
            this.eden.clear();
        }
        this.eden.put(k,v);
    }



}

LinkedHashMap

当然,对于本地缓存,我们也可以使用 基于 LinkedHashMap 的实现缓存工具类,基于volatile 实现LRU策略线程安全缓存 

package com.liruilong.common.util.concurrentcache;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @Author Liruilong
 * @Date 2020/8/11 14:19
 * @Description: 基于 LinkedHashMap 的缓存实现
 */
public class LinkedHashMapCache<K,V> {
    private  final Map<K,V> eden;


    public LinkedHashMapCache(Builder builder) {
        this.eden = builder.eden;
    }

    public static class Builder<K,V> {

        private volatile  Map<K,V> eden;
        private int size;

        public Builder(int size){
            this.size = rangeCheck(size,Integer.MAX_VALUE,"缓存容器初始化容量异常");

            this.eden = new LinkedHashMap<K,V>(size,0.75f,true){
                @Override
                protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
                    return size() >= size;
                }
            };
        }

        private static int rangeCheck(int val, int i, String arg) {
            if (val < 0 || val > i) {
                throw new IllegalArgumentException(arg + ":" + val);
            }
            return  val;
        }

        public LinkedHashMapCache build(){
            return new LinkedHashMapCache(this);
        }
    }

    public V get(K k){
       return eden.get(k);
    }

    public void put(K k,V v){
        this.eden.put(k,v);
    }

    public static void main(String[] args) {
        LinkedHashMapCache cache = new LinkedHashMapCache.Builder<String,Integer>(3).build();
        for (int i = 0; i < 5; i++) {
            cache.put(i+"",i);
        }
        for (int i = 0; i < 5; i++) {
            System.out.println(cache.get(i + ""));
        }
    }

}

测试文档

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。