title: Java并发编程入门(十三)读写锁和缓存模板 categories: Java并发编程
tag:
提到读写锁,都能想到是锁优化方式之一的锁分离,实现效果是读读不互斥,读写互斥,写写互斥。
读写锁本身比较简单,下面通过一个例子看看读写锁的使用。
1.Cache是一个抽象类,实现了缓存的基本方法,子类只需要实现init方法初始化缓存数据, 读写锁在此类中应用。
2.CacheManager是缓存管理类,缓存相关的操作均以它作为入口,集中管理。
3.CacheKey是个常量定义类,定义了每个缓存的key,例如证件类型缓存key,行业缓存key等等,访问指定缓存时通过定义的常量key来访问。
import java.util.HashMap; import java.util.Map; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; /** * @ClassName Cache * @Description 缓存抽象类 * @Author 铿然一叶 * @Date 2019/10/6 10:59 * @Version 1.0 * javashizhan.com **/ public abstract class Cache<K,V> { final Map<K, V> m = new HashMap<K,V>(); final ReadWriteLock rwl = new ReentrantReadWriteLock(); final Lock r = rwl.readLock(); final Lock w = rwl.writeLock(); public V get(K key) { r.lock(); try { return m.get(key); } finally { r.unlock(); } } public V put(K key, V value) { w.lock(); try { return m.put(key, value); } finally { w.unlock(); } } public V remove(K key) { w.lock(); try { return m.remove(key); } finally { w.unlock(); } } /** * 模板方法,调用子类实现的init方法 */ void _init() { w.lock(); try { init(); } finally { w.unlock(); } } /** * 缓存初始化,子类实现 */ protected abstract void init(); } 复制代码
public class CacheKey { public static final Integer CERTIFICATE_TYPE = 1001; public static final Integer INDUSTRY = 1002; } 复制代码
import java.util.Hashtable; import java.util.Map; /** * @ClassName CacheManager * @Description 缓存管理 * @Author 铿然一叶 * @Date 2019/10/6 11:11 * @Version 1.0 * javashizhan.com **/ public class CacheManager<K, V> { private Map<Integer, Cache<K, V>> cacheMap = new Hashtable<Integer, Cache<K, V>>(); /** 私有构造器 */ private CacheManager() {} private static CacheManager cacheManager; /** * 单例模式 * @return */ public static CacheManager getInstance() { if (null == cacheManager) { synchronized (CacheManager.class) { if (null == cacheManager) { cacheManager = new CacheManager(); } } } return cacheManager; } /** * 注册缓存 * @param cacheKey 缓存key * @param cache */ public void registerCache(Integer cacheKey, Cache<K, V> cache) { cache._init(); cacheMap.put(cacheKey, cache); } /** * 从指定缓存中获取数据 * @param cacheKey 缓存Key * @param key * @return */ public V getValue(Integer cacheKey, K key) { Cache<K, V> cache = cacheMap.get(cacheKey); return cache.get(key); } /** * 设置缓存 * @param cacheKey 缓存Key * @param key * @param value */ public void put(Integer cacheKey, K key, V value) { Cache<K, V> cache = cacheMap.get(cacheKey); cache.put(key, value); } /** * 从指定缓存中删除数据 * @param cacheKey 缓存Key * @param key */ public V remove(Integer cacheKey, K key) { Cache<K, V> cache = cacheMap.get(cacheKey); return cache.remove(key); } } 复制代码
/** * @ClassName IndustryCache * @Description 行业缓存 * @Author 铿然一叶 * @Date 2019/10/6 11:38 * @Version 1.0 * javashizhan.com **/ public class IndustryCache extends Cache { /** * 初始化缓存,可以自行实现,例如从数据库中读取数据 */ @Override public void init() { put("01", "建筑建材"); put("02", "冶金矿产"); put("03", "石油化工"); put("04", "水利水电"); } } 复制代码
/** * @ClassName CertificateTypeCache * @Description 证件类型缓存 * @Author 铿然一叶 * @Date 2019/10/6 11:32 * @Version 1.0 * javashizhan.com **/ public class CertificateTypeCache extends Cache { /** * 初始化缓存,可以自行实现,例如从数据库中读取数据 */ @Override public void init() { put("01","身份证"); put("02","护照"); put("03","军官证"); put("04","学生证"); } } 复制代码
public class CacheTest { public static void main(String[] args) { //初始化缓存 Cache certificateTypeCache = new CertificateTypeCache(); Cache industryCache = new IndustryCache(); CacheManager.getInstance().registerCache(CacheKey.CERTIFICATE_TYPE, certificateTypeCache); CacheManager.getInstance().registerCache(CacheKey.CERTIFICATE_TYPE, industryCache); //获取证件类型 Object value = CacheManager.getInstance().getValue(CacheKey.CERTIFICATE_TYPE,"01"); System.out.println("value: " + value); //证件类型缓存添加数据 CacheManager.getInstance().put(CacheKey.CERTIFICATE_TYPE, "99", "警官证"); value = CacheManager.getInstance().getValue(CacheKey.CERTIFICATE_TYPE,"99"); System.out.println("value: " + value); //证件类型缓存移除数据 CacheManager.getInstance().remove(CacheKey.CERTIFICATE_TYPE, "99"); value = CacheManager.getInstance().getValue(CacheKey.CERTIFICATE_TYPE,"99"); System.out.println("value: " + value); } } 复制代码
输出日志:
value: 建筑建材 value: 警官证 value: null 复制代码
1.缓存初始化方式可以是懒加载或者勤快加载,可以根据需要实现。
2.Spring中勤快加载可以在spring初始化过程中完成,例如启动类中,另外一种比较好的方式是每个缓存类自行完成加载和注册,代码参考如下:
import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; /** * @ClassName IndustryCache * @Description TODO * @Author 铿然一叶 * @Date 2019/10/6 13:08 * @Version 1.0 * javashizhan.com **/ @Component public class IndustryCache extends Cache { /** * 可以自行实现,例如从数据库中读取数据 */ @Override public void init() { put("01", "建筑建材"); put("02", "冶金矿产"); put("03", "石油化工"); put("04", "水利水电"); } @PostConstruct public void register() { CacheManager.getInstance().registerCache(CacheKey.INDUSTRY, this); } } 复制代码
1.首先是在每个缓存类上添加@Component注解,使得Spring启动时会加载这个类到内存中。
2.其次在每个缓存类中实现一个缓存注册方法,并添加@PostConstruct注解,使得缓存类被spring实例化后会自动调用该方法。
这样每个缓存的初始化和注册就只和自己有关,实现了职责分离,内聚以及解耦。
end.
相关阅读:
Java并发编程(一)知识地图
Java并发编程(二)原子性
Java并发编程(三)可见性
Java并发编程(四)有序性
Java并发编程(五)创建线程方式概览
Java并发编程入门(六)synchronized用法
Java并发编程入门(七)轻松理解wait和notify以及使用场景
Java并发编程入门(八)线程生命周期
Java并发编程入门(九)死锁和死锁定位
Java并发编程入门(十)锁优化
Java并发编程入门(十一)限流场景和Spring限流器实现
Java并发编程入门(十二)生产者和消费者模式-代码模板站点: javashizhan.com/
微信公众号: