非分布式高并发缓存实例


title: 非分布式高并发缓存实例
tags: 新建,模板,小书匠
grammar_cjkRuby: true

欢迎使用 {小书匠}(xiaoshujiang)编辑器,您可以通过设置里的修改模板来改变新建文章的内容。

缓存机制的实现现有两种实现方式

	1. 利用现有的缓存框架,redis等nosql数据库.
		优点: 稳定,适用分布式.数据共享.
		缺点: 需要学习成本对新手不友好,较重.
	2. 手写的缓存工具
		优点: 便于学习,轻量级
		缺点: 不适用分布式

基本代码如下

缓存工具的基本实现

package com.word.cache;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 非分布式手写高并发缓存实例
 */
public class Cache {

	//键值对集合
	private final static Map map = new HashMap<>();

	//定时器线程池
	private final static ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();

	/**
	 *
	 * 添加缓存
	 * @param key
	 * @param data
	 */
	public synchronized static void put(String key,Object data){
		put(key,data,0);
	}

	/**
	 * 添加缓存
	 * @param key  键
	 * @param data 值
	 * @param expire 过期时间(ms) 0 表示无限长
	 */
	public synchronized static void put(String key,Object data,int expire){
		//清除原键值对
		Cache.remove(key);
		//设置过期时间
		if (expire > 0 ){
			Future future = scheduledExecutorService.schedule(()-> {
				//过去清除该缓存数据
				synchronized (Cache.class){
					map.remove(key);
				}
			},expire,TimeUnit.MILLISECONDS);
			map.put(key,new Entity(data,future));
		}else {
			//不设置过期时间
			map.put(key,new Entity(data,null));
		}
	}

	/**
	 * 读取缓存
	 * @param key
	 * @return
	 */
	public synchronized static Object get(String key){
		Entity entity = map.get(key);
		return  entity == null? null:entity.getValue();
	}

	/**
	 * 读取缓存
	 * @param key
	 * @param clazz
	 * @param 
	 * @return
	 */
	public synchronized static  T get(String key,Class clazz){
		return clazz.cast(Cache.get(key));
	}

	/**
	 * 清除缓存
	 * @param key
	 * @return
	 */
	public synchronized static Object remove(String key){
		//清除原缓存数据
		Entity entity = map.remove(key);
		if (entity == null) return  null;
		//清除原键值对定时器
		Future future = entity.getFuture();
		if (future != null) future.cancel(true);
		return  entity.getValue();
	}

	/**
	 * 查询当前缓存的键值对数量
	 * @return
	 */
	public synchronized static int size(){
		return map.size();
	}




	/**
	 * 缓存实体类
	 */
	private static class Entity{
		//存储的数据
		private T value;

		//定时器
		private Future future;

		public Entity(T value, Future future) {
			this.value = value;
			this.future = future;
		}

		/**
		 * 获取数据
		 * @return
		 */
		public T getValue() {
			return value;
		}

		/**
		 * 获取定时器
		 * @return
		 */
		public Future getFuture() {
			return future;
		}
	}

}

缓存工具测试类

package com.word.cache;

import java.util.concurrent.*;

/**
 * 测试缓存
 */
public class CacheTest {
//自定义线程池
    public static ExecutorService executorService = new ThreadPoolExecutor(2,10,0L, TimeUnit.SECONDS,new LinkedBlockingQueue(32),new ThreadPoolExecutor.CallerRunsPolicy());

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        String key = "id";
        //不设置过期时间
        System.err.println("***********************不设置过期时间************************");
        Cache.put(key,123);
        System.out.println("key:"+key+",value:"+Cache.get(key));
        System.out.println("key:"+key+",value:"+Cache.get(key));
        System.out.println("key:"+key+",value:"+Cache.get("trykill"));
        //设置过期时间
        System.err.println("***********************设置过期时间************************");
        Cache.put(key,"123456",1000);
        System.out.println("key:"+key+",value:"+Cache.get(key));
        Thread.sleep(2000);
        System.out.println("key:"+key+",value:"+Cache.get(key));
        /*####################################高并发测试#######################################*/
        Future[] futures = new Future[100];
        /**put***/
        long start = System.currentTimeMillis();
        for (int i = 0; i<100;i++){
            futures[i] = executorService.submit(()->{
                long start1 = System.currentTimeMillis();
                for (int j = 0;j<100000;j++){
                    Cache.put(Thread.currentThread().getName()+j,j);
                }
                System.err.println("&&&&&&:"+Thread.currentThread().getName()+",添加耗时:"+(System.currentTimeMillis() - start1));
            });
        }
        //等待执行完毕打印持续时间
        for (Future future : futures){
            future.get();
        }

        System.err.println("添加耗时:"+(System.currentTimeMillis() - start));
        /**get***/
        long startGet = System.currentTimeMillis();
        for (int i = 0; i < 100;i++){
            futures[i] = executorService.submit(()->{
                for (int j = 0;j<100000;j++){
                    Cache.get(Thread.currentThread().getName()+j);
                }
            });
        }
        //等待执行完毕打印持续时间
        for (Future future : futures){
            future.get();
        }

        System.err.println("查询耗时:"+(System.currentTimeMillis() - startGet));
        System.err.println("缓存容量:"+Cache.size());
    }
}

结果

***********************不设置过期时间************************
key:id,value:123
key:id,value:123
key:id,value:null
***********************设置过期时间************************
key:id,value:123456
key:id,value:null
&&&&&&:pool-1-thread-1,添加耗时:465
&&&&&&:pool-1-thread-4,添加耗时:470
&&&&&&:pool-1-thread-7,添加耗时:479
&&&&&&:pool-1-thread-5,添加耗时:485
&&&&&&:pool-1-thread-10,添加耗时:504
&&&&&&:pool-1-thread-6,添加耗时:537
&&&&&&:main,添加耗时:1357
...省略...
&&&&&&:pool-1-thread-2,添加耗时:170
添加耗时:4112
查询耗时:1957
缓存容量:1100000

你可能感兴趣的:(学习笔记)