package com.cy.java.cache; /\*\* Cache接口设计\*/ public interface Cache { public void putObject(Object key,Object value); public Object getObject(Object key); public Object removeObject(Object key); public void clear(); public int size(); }
场景应用:
package com.cy.java.cache; import java.util.HashMap; import java.util.Map; /**负责真正存储数据的一个对象,将数据存储到一个map中*/ public class PerpetualCache implements Cache { /** 特色:线程不安全,key不容许重复,不能保证key的顺序 */ private Map<Object,Object> cache=new HashMap<>(); @Override public void putObject(Object key, Object value) { cache.put(key, value); } @Override public Object getObject(Object key) { return cache.get(key); } @Override public Object removeObject(Object key) { return cache.remove(key); } @Override public void clear() { cache.clear(); } @Override public int size() { return cache.size(); } @Override public String toString() { return cache.toString(); } public static void main(String\[\] args) { Cache cache=new PerpetualCache(); cache.putObject("A", 100); cache.putObject("B", 200); cache.putObject("C", 300); System.out.println(cache); cache.removeObject("D"); cache.clear(); System.out.println(cache.size()); } }
场景应用:并发环境
package com.cy.java.cache; /**线程安全的cache对象*/ public class SynchronizedCache implements Cache{ private Cache cache; public SynchronizedCache(Cache cache) { this.cache=cache; } @Override public synchronized void putObject(Object key, Object value) { cache.putObject(key, value); } @Override public synchronized Object getObject(Object key) { // TODO Auto-generated method stub return cache.getObject(key); } @Override public synchronized Object removeObject(Object key) { // TODO Auto-generated method stub return cache.removeObject(key); } @Override public synchronized void clear() { cache.clear(); } @Override public synchronized int size() { return cache.size(); } @Override public String toString() { return cache.toString(); } public static void main(String\[\] args) { SynchronizedCache cache= new SynchronizedCache(new PerpetualCache()); cache.putObject("A", 100); cache.putObject("B", 200); cache.putObject("C", 300); System.out.println(cache); } }
思考:对于SynchronizedCache 有什么优点,劣势?java
package com.cy.java.cache; /** 用于记录命中率的日志cache*/ public class LoggingCache implements Cache { private Cache cache; /**记录请求次数*/ private int requests; /**记录命中次数*/ private int hits; public LoggingCache(Cache cache) { this.cache=cache; } @Override public void putObject(Object key, Object value) { cache.putObject(key, value); } @Override public Object getObject(Object key) { requests++; Object obj=cache.getObject(key); if(obj!=null)hits++; System.out.println("Cache hit Ratio : "+hits\*1.0/requests); return obj; } @Override public Object removeObject(Object key) { return cache.removeObject(key); } @Override public void clear() { cache.clear(); } @Override public int size() { return cache.size(); } @Override public String toString() { // TODO Auto-generated method stub return cache.toString(); } public static void main(String\[\] args) { SynchronizedCache cache= new SynchronizedCache( new LoggingCache( new PerpetualCache())); cache.putObject("A", 100); cache.putObject("B", 200); cache.putObject("C", 300); System.out.println(cache); cache.getObject("D"); cache.getObject("A"); } }
思考:你以为LoggingCache记录日志的方式有什么很差的地方?(信息的完整性,同步问题)算法
应用场景:基于LRU算法的的基本实现
package com.cy.java.cache; import java.util.LinkedHashMap; import java.util.Map; /** 缓存淘汰策略:LRU(最近最少使用算法)*/ public class LruCache implements Cache { private Cache cache; /**经过此属性记录要移除的数据对象*/ private Object eldestKey; /**经过此map记录key的访问顺序*/ private Map<Object,Object> keyMap; @SuppressWarnings("serial") public LruCache(Cache cache,int maxCap) { this.cache=cache; //LinkedHashMap能够记录key的添加顺序或者访问顺序 this.keyMap= new LinkedHashMap<Object,Object>(maxCap, 0.75f, true) {//accessOrder //此方法每次执行keyMap的put操做时调用 @Override protected boolean removeEldestEntry (java.util.Map.Entry<Object, Object> eldest) { boolean isFull=size()>maxCap; if(isFull)eldestKey=eldest.getKey(); return isFull; } }; } @Override public void putObject(Object key, Object value) { //存储数据对象 cache.putObject(key, value); //记录key的访问顺序,假如已经满了,就要从cache中移除数据 keyMap.put(key, key);//此时会执行keyMap对象的removeEldestEntry if(eldestKey!=null) { cache.removeObject(eldestKey); eldestKey=null; } } @Override public Object getObject(Object key) { keyMap.get(key);//记录key的访问顺序 return cache.getObject(key); } @Override public Object removeObject(Object key) { return cache.removeObject(key); } @Override public void clear() { cache.clear(); keyMap.clear(); } @Override public int size() { return cache.size(); } @Override public String toString() { return cache.toString(); } public static void main(String\[\] args) { SynchronizedCache cache= new SynchronizedCache( new LoggingCache( new LruCache(new PerpetualCache(),3))); cache.putObject("A", 100); cache.putObject("B", 200); cache.putObject("C", 300); cache.getObject("A"); cache.getObject("C"); cache.putObject("D", 400); cache.putObject("E", 500); System.out.println(cache); } }
package com.cy.java.cache; import java.util.Deque; import java.util.LinkedList; /** * FifoCache :基于FIFO算法(对象满了要按先进先出算法移除对象)实现cache对象 */ public class FifoCache implements Cache{ /**借助此对象存储数据*/ private Cache cache; /**借助此队列记录key的顺序*/ private Deque<Object> keyOrders; /**经过此变量记录cache能够存储的对象个数*/ private int maxCap; public FifoCache(Cache cache,int maxCap) { this.cache=cache; keyOrders=new LinkedList<>(); this.maxCap=maxCap; } @Override public void putObject(Object key, Object value) { //1.记录key的顺序(起始就是存储key,添加在队列最后位置) keyOrders.addLast(key); //2.检测cache中数据是否已满,满了则移除。 if(keyOrders.size()>maxCap) { Object eldestKey=keyOrders.removeFirst(); cache.removeObject(eldestKey); } //3.放新的对象 cache.putObject(key, value); } @Override public Object getObject(Object key) { return cache.getObject(key); } @Override public Object removeObject(Object key) { Object obj=cache.removeObject(key); keyOrders.remove(key); return obj; } @Override public void clear() { cache.clear(); keyOrders.clear(); } @Override public int size() { return cache.size(); } @Override public String toString() { // TODO Auto-generated method stub return cache.toString(); } public static void main(String\[\] args) { Cache cache= new SynchronizedCache( new LoggingCache( new FifoCache( new PerpetualCache(),3))); cache.putObject("A",100); cache.putObject("B",200); cache.putObject("C",300); cache.getObject("A"); cache.putObject("D",400); cache.putObject("E",500); System.out.println(cache); } }
场景:存储到cache的是对象的字节
package com.cy.java.cache; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class SerializedCache implements Cache { private Cache cache; public SerializedCache(Cache cache) { this.cache=cache; } /**序列化*/ private byte\[\] serialize(Object value) { //1.构建流对象 ByteArrayOutputStream bos=null; ObjectOutputStream oos=null; try { //1.2构建字节数组输出流,此流对象内置可扩容的数组。 bos=new ByteArrayOutputStream(); //1.3构建对象输出流 oos=new ObjectOutputStream(bos); //2.对象序列化 oos.writeObject(value); //此时对象会以字节的方式写入到字节数组输出流 oos.flush(); return bos.toByteArray(); }catch (Exception e) { throw new RuntimeException(e); }finally { //3.关闭流对象 if(bos!=null) try{bos.close();bos=null;}catch(Exception e) {} if(oos!=null) try{oos.close();oos=null;}catch (Exception e2) {} } } /**反序列化*/ public Object deserialize(byte\[\] value) { //1.建立流对象 ByteArrayInputStream bis=null; ObjectInputStream ois=null; try { //1.1构建字节数组输入流,此对象能够直接读取数组中的字节信息 bis=new ByteArrayInputStream(value); //1.2构建对象输入流(对象反序列化) ois=new ObjectInputStream(bis); //2.反序列化对象 Object obj=ois.readObject(); return obj; }catch(Exception e) { throw new RuntimeException(e); }finally { //3.关闭流对象 if(bis!=null) try{bis.close();bis=null;}catch(Exception e) {} if(ois!=null) try{ois.close();ois=null;}catch (Exception e2) {} } } @Override public void putObject(Object key, Object value) { cache.putObject(key, serialize(value)); } @Override public Object getObject(Object key) { return deserialize((byte\[\])cache.getObject(key)); } @Override public Object removeObject(Object key) { return cache.removeObject(key); } @Override public void clear() { cache.clear(); } @Override public int size() { return cache.size(); } public static void main(String\[\] args) { Cache cache=new SerializedCache(new PerpetualCache()); cache.putObject("A", 200); cache.putObject("B", 300); Object v1=cache.getObject("A"); Object v2=cache.getObject("A"); System.out.println(v1==v2); System.out.println(v1); System.out.println(v2); } }
应用场景:内存不足时淘汰缓存中数据
package com.cy.java.cache; import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; /**软引用*/ public class SoftCache implements Cache { private Cache cache; private ReferenceQueue<Object> garbageOfRequenceQueue= new ReferenceQueue<>(); public SoftCache(Cache cache) { this.cache=cache; } @Override public void putObject(Object key, Object value) { //1.移除一些垃圾对象(Soft引用引用的已经被回收的对象) removeGarbageObjects(); //2.将对象存储到cache(key不变,Value为为soft引用对象) cache.putObject(key, new SoftEntry(key, value, garbageOfRequenceQueue)); } @Override public Object getObject(Object key) { //1.基于key获取软引用对象并判断 SoftEntry softEntry=(SoftEntry)cache.getObject(key); if(softEntry==null)return null; //2.基于软引用对象获取它引用的对象并判断 Object target = softEntry.get(); if(target==null)cache.removeObject(key); return target; } @Override public Object removeObject(Object key) { //1.移除一些垃圾对象(Soft引用引用的已经被回收的对象) removeGarbageObjects(); //2.从cache中移除对象 Object removedObj=cache.removeObject(key); return removedObj; } @Override public void clear() { //1.移除一些垃圾对象(Soft引用引用的已经被回收的对象) removeGarbageObjects(); //2.清空cache cache.clear(); } @Override public int size() { removeGarbageObjects(); return cache.size(); } private void removeGarbageObjects() { SoftEntry softEntry=null; //1.从引用队列中获取已经被GC的一些对象的引用 while((softEntry= (SoftEntry)garbageOfRequenceQueue.poll())!=null){ //softEntry不为null表示softEntry引用的对象已经被移除 //2.从cache中将对象引用移除。 cache.removeObject(softEntry.key); } } /\*\*定义软引用类型\*/ private static class SoftEntry extends SoftReference<Object\>{ private final Object key; public SoftEntry(Object key, Object referent, ReferenceQueue<? super Object> rQueue) { super(referent, rQueue); this.key=key; } } @Override public String toString() { // TODO Auto-generated method stub return cache.toString(); } public static void main(String\[\] args) { Cache cache=new SoftCache(new PerpetualCache()); cache.putObject("A", new byte\[1024\*1024\]); cache.putObject("B", new byte\[1024\*1024\]); cache.putObject("C", new byte\[1024\*1024\]); cache.putObject("D", new byte\[1024\*1024\]); cache.putObject("E", new byte\[1024\*1024\]); System.out.println(cache.size()); System.out.println(cache); } }
应用场景:GC触发清除缓存对象
package com.cy.java.cache; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; /\*\*弱引用\*/ public class WeakCache implements Cache { private Cache cache; private ReferenceQueue<Object> garbageOfRequenceQueue= new ReferenceQueue<>(); public WeakCache(Cache cache) { this.cache=cache; } @Override public void putObject(Object key, Object value) { //1.移除一些垃圾对象(Soft引用引用的已经被回收的对象) removeGarbageObjects(); //2.将对象存储到cache(key不变,Value为为soft引用对象) cache.putObject(key, new WeakEntry(key, value, garbageOfRequenceQueue)); } @Override public Object getObject(Object key) { //1.基于key获取软引用对象并判断 WeakEntry softEntry=(WeakEntry)cache.getObject(key); if(softEntry==null)return null; //2.基于软引用对象获取它引用的对象并判断 Object target = softEntry.get(); if(target==null)cache.removeObject(key); return target; } @Override public Object removeObject(Object key) { //1.移除一些垃圾对象(Soft引用引用的已经被回收的对象) removeGarbageObjects(); //2.从cache中移除对象 Object removedObj=cache.removeObject(key); return removedObj; } @Override public void clear() { //1.移除一些垃圾对象(Soft引用引用的已经被回收的对象) removeGarbageObjects(); //2.清空cache cache.clear(); } @Override public int size() { removeGarbageObjects(); return cache.size(); } private void removeGarbageObjects() { WeakEntry softEntry=null; //1.从引用队列中获取已经被GC的一些对象的引用 while((softEntry= (WeakEntry)garbageOfRequenceQueue.poll())!=null) { //softEntry不为null表示softEntry引用的对象已经被移除 //2.从cache中将对象引用移除。 cache.removeObject(softEntry.key); } } /**定义软引用类型*/ private static class WeakEntry extends WeakReference<Object\>{ private final Object key; public WeakEntry(Object key, Object referent, ReferenceQueue<? super Object> rQueue) { super(referent, rQueue); this.key=key; } } @Override public String toString() { return cache.toString(); } public static void main(String\[\] args) { Cache cache=new WeakCache(new PerpetualCache()); cache.putObject("A", new byte\[1024\*1024\]); cache.putObject("B", new byte\[1024\*1024\]); cache.putObject("C", new byte\[1024\*1024\]); cache.putObject("D", new byte\[1024\*1024\]); cache.putObject("E", new byte\[1024\*1024\]); cache.putObject("F", new byte\[1024\*1024\]); cache.putObject("G", new byte\[1024\*1024\]); System.out.println(cache.size()); System.out.println(cache); } }
package com.cy.java.cache; import java.util.concurrent.locks.ReentrantReadWriteLock; /** * 构建线程安全对象,基于ReentrantReadWriteLock对象实现读写锁应用。 * @author qilei */ public class ReentrantLockCache implements Cache { private Cache cache; /** * 此对象提供了读锁,写锁应用方式. * 1)写锁:排他锁 * 2)读锁:共享锁 * 说明:读写不能同时执行。 */ private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); public ReentrantLockCache(Cache cache) { this.cache=cache; // TODO Auto-generated constructor stub } @Override public void putObject(Object key, Object value) { readWriteLock.writeLock().lock(); try { cache.putObject(key, value); }finally { readWriteLock.writeLock().unlock(); } } @Override public Object getObject(Object key) { readWriteLock.readLock().lock(); try { Object object=cache.getObject(key); return object; }finally{ readWriteLock.readLock().unlock(); } } @Override public Object removeObject(Object key) { readWriteLock.writeLock().lock(); try { Object object=cache.removeObject(key); return object; }finally{ readWriteLock.writeLock().unlock(); } } @Override public void clear() { readWriteLock.writeLock().lock(); try { cache.clear(); }finally{ readWriteLock.writeLock().unlock(); } } @Override public int size() { readWriteLock.readLock().lock(); try { int size=cache.size(); return size; }finally{ readWriteLock.readLock().unlock(); } } }
第一步:添加依赖
` <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency> `
第二步:添加配置文件logback.xml (参考项目代码)
<?xml version="1.0" encoding="UTF-8"?> <configuration> <logger name="com.cy" level="TRACE" /> <appender name="FILE" class\="ch.qos.logback.core.rolling.RollingFileAppender"\> <rollingPolicy class\="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"\> <!--文件路径,定义了日志的切分方式----把每一天的日志归档到一个文件中,以防止日志填满整个磁盘空间 --> <fileNamePattern>logs/context-log.%d{yyyy-MM-dd}.log </fileNamePattern> <!--只保留最近30天的日志 --> <maxHistory>30</maxHistory> </rollingPolicy> <encoder charset="UTF-8"\> <pattern>\[%-5level\] %date --%thread-- \[%logger\] %msg %n</pattern> </encoder> </appender> <appender name="ASYNC\_FILE" class\="ch.qos.logback.classic.AsyncAppender"\> <discardingThreshold>0</discardingThreshold> <queueSize>256</queueSize> <appender-ref ref="FILE" /> </appender> <root level="debug"\> <appender-ref ref="ASYNC\_FILE" /> </root> </configuration>
第三步:构建AsyncLoggingCache
package com.cy.java.cache; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * 经过此对象异步记录查询操做的命中率 * 1)选择日志库 * 2)执行异步写操做。 */ public class AsyncLoggingCache implements Cache { //日志门面应用 private static Logger log=LoggerFactory.getLogger(LoggingCache.class); private Cache cache; /**表示请求次数*/ private int requests; /**命中次数(命中表示从缓存中取到数据了)*/ private int hits; public AsyncLoggingCache(Cache cache) { this.cache=cache; } @Override public void putObject(Object key, Object value) { cache.putObject(key, value); } @Override public Object getObject(Object key) { requests++; Object obj=cache.getObject(key); if(obj!=null)hits++; //记录日志耗时 log.info("Cache hit Ratio:{}",hits\*1.0/requests); return obj; } @Override public Object removeObject(Object key) { return cache.removeObject(key); } @Override public void clear() { cache.clear(); } @Override public int size() { return cache.size(); } public static void main(String\[\] args) { Cache cache= new AsyncLoggingCache(new PerpetualCache()); cache.putObject("A", 100); cache.putObject("B", 200); cache.putObject("C", 300); cache.putObject("D", 400); //System.out.println(cache); cache.getObject("E"); cache.getObject("A"); cache.getObject("B"); } }
第一步:添加依赖
<dependency> <groupId>com.esotericsoftware</groupId> <artifactId>kryo</artifactId> <version>5.0.0-RC5</version> </dependency>
第二步:构建项目工具类
public class KryoUtils { /** * 多线程并发执行时,可能会出现线程不安全,具体缘由是什么? * 1)多个线程的并发 * 2)多个线程有数据共享 * 3)多个线程在共享数据集上的操做不是原子操做 * * 分析:当出现了线程不安全,如何进行修改来保证线程安全 * 1)将多线程改成单线程。 * 2)取消共享 (例如在当前应用中咱们一个线程一个Kryo对象) * 3)加锁+CAS * * ThreadLocal提供了这样的一种机制: * 1)能够将对象绑定到当前线程(实际上是将对象存储到当前线程的map中) * 2)能够从当前线程获取绑定的对象(从当前线程的map中获取对象) */ static private final ThreadLocal<Kryo> kryos = new ThreadLocal<Kryo>() { protected Kryo initialValue() { Kryo kryo = new Kryo(); // Configure the Kryo instance. kryo.setRegistrationRequired(false); //.... return kryo; }; }; public static Object deserialize(byte\[\] array){ Kryo kryo=kryos.get(); Input input = new Input(new ByteArrayInputStream(array)); Object obj=kryo.readClassAndObject(input); return obj; } public static byte\[\] serialize(Object object){ //从当前线程获取kryo对象,当前线程没有会调用ThreadLocal的initialValue方法建立对象并绑定线程 Kryo kryo=kryos.get(); ByteArrayOutputStream bos=new ByteArrayOutputStream(); Output output = new Output(bos); kryo.writeClassAndObject(output, object); output.close(); return bos.toByteArray(); } }
public class KryoSerializedCache implements Cache { private Cache cache; public KryoSerializedCache(Cache cache) { this.cache=cache; } @Override public void putObject(Object key, Object value) { //1.将对象序列化 byte\[\] array=KryoUtils.serialize(value); //2.将序列化后的字节数组引用存储到cache cache.putObject(key,array); } @Override public Object getObject(Object key) { //1.基于key获取缓存中的字节数组引用 byte\[\] array=(byte\[\])cache.getObject(key); //2.将字节数组反序列化为对象 return KryoUtils.deserialize(array); } @Override public Object removeObject(Object key) { return KryoUtils.deserialize((byte\[\])cache.removeObject(key)); } @Override public void clear() { cache.clear(); } @Override public int size() { return cache.size(); } public static void main(String\[\] args) { Cache cache=new KryoSerializedCache(new PerpetualCache()); cache.putObject("A", 500); Object a1=cache.getObject("A"); Object a2=cache.getObject("A"); System.out.println("a1="+a1); System.out.println("a2="+a2); System.out.println(a1==a2);//false } }