版权声明:本文为HCG原创文章,未经博主允许不得转载。请联系[email protected] https://blog.csdn.net/qq_39455116/article/details/86650037
用锁降级或者synchronized实现一个缓存
参考了很多网上的代码,发现大部分都是一模一样的,而且是错的,根本没有实现缓存
自己找了很久,发现了他们分别对应的问题A和B
// syn实现缓存里面最关键的步骤
synchronized (map) {
value = map.get(key);// A 这一行不能少
if (value == null) {
value = "abc";
if (value == null) {
try {
rwl.readLock().unlock();//关闭读锁
rwl.writeLock().lock();//开启写锁
// B 这个地方需要再检查一下,不检查的话,这个缓存就实现不了
value = map.get(key);
代码如下:
package duoxiancheng.reentrantLock.read;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class CacheMap {
//声明一个map,用来作为缓存模型
private static Map<String, Object> map = new HashMap<String, Object>();
//声明一个读写锁
private static ReadWriteLock rwl = new ReentrantReadWriteLock();
//用synchronized关键字实现一个缓存
public Object synGetValue(String key) {
Object value = map.get(key);
if (value == null) {
synchronized (map) {
value = map.get(key); // A
if (value == null) {
value = "abc";//这里是去数据库查询
map.put(key, value);//将数据放到缓存模型中
System.out.println(Thread.currentThread().getName() + "syn方式实现,put也只执行一次");
}
}
}
return value;
}
//用读写锁的锁降级实现一个缓存
public Object getValue(String key) {
Object value = null;
try {
rwl.readLock().lock();//开启读锁
value = map.get(key);
if (value == null) {
try {
rwl.readLock().unlock();//关闭读锁
rwl.writeLock().lock();//开启写锁
//这个地方需要再检查一下,不检查的话,这个缓存就实现不了
value = map.get(key); //B
if (value == null) {
value = "abc";//这里是去数据库查询
map.put(key, value);//将数据放到缓存模型中
System.out.println(Thread.currentThread().getName() + "=======这个只执行一次=========");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
rwl.writeLock().unlock();//关闭写锁
rwl.readLock().lock();//开启读锁
//System.out.println(Thread.currentThread().getName() + "----2----");
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
rwl.readLock().unlock();//关闭读锁
//System.out.println(Thread.currentThread().getName() + "----3----");
}
return value;
}
public static void main(String[] args) {
CacheMap cacheMap = new CacheMap();
for (int i = 0; i < 10; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + cacheMap.getValue("readWrite"));
}, "--------readWrite线程" + i).start();
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + cacheMap.synGetValue("syn"));
}, "synchronized线程" + i).start();
}
}
}
9. 结果分析
--------readWrite线程0=======这个只执行一次=========
--------readWrite线程0abc
synchronized线程0syn方式实现,put也只执行一次
synchronized线程0abc
synchronized线程1abc
--------readWrite线程1abc
synchronized线程2abc
--------readWrite线程2abc
--------readWrite线程3abc
synchronized线程3abc
synchronized线程4abc
--------readWrite线程5abc
--------readWrite线程4abc
--------readWrite线程6abc
synchronized线程6abc
--------readWrite线程7abc
synchronized线程5abc
--------readWrite线程8abc
synchronized线程7abc
--------readWrite线程9abc
synchronized线程8abc
synchronized线程9abc
发现满足了线程安全的定义,只有一个线程往其中put了数据,实现了缓存
但是其实如果只是缓存的存的话,用synchronized会更简单一些,效率两个都差不多