提到读写锁,都能想到是锁优化方式之一的锁分离,实现效果是读读不互斥,读写互斥,写写互斥。java
读写锁自己比较简单,下面经过一个例子看看读写锁的使用。spring
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初始化过程当中完成,例如启动类中,另一种比较好的方式是每一个缓存类自行完成加载和注册,代码参考以下:bash
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实例化后会自动调用该方法。ide
这样每一个缓存的初始化和注册就只和本身有关,实现了职责分离,内聚以及解耦。post
end.
相关阅读:
Java并发编程(一)知识地图
Java并发编程(二)原子性
Java并发编程(三)可见性
Java并发编程(四)有序性
Java并发编程(五)建立线程方式概览
Java并发编程入门(六)synchronized用法
Java并发编程入门(七)轻松理解wait和notify以及使用场景
Java并发编程入门(八)线程生命周期
Java并发编程入门(九)死锁和死锁定位
Java并发编程入门(十)锁优化
Java并发编程入门(十一)限流场景和Spring限流器实现
Java并发编程入门(十二)生产者和消费者模式-代码模板
Java并发编程入门(十四)CountDownLatch应用场景
Java并发编程入门(十五)CyclicBarrier应用场景
Java并发编程入门(十六)秒懂线程池差异
Java并发编程入门(十七)一图掌握线程经常使用类和接口
Java并发编程入门(十八)再论线程安全
Java极客站点: javageektour.com/