我使用的synchronized和ReentrantLock对吗?

lingli219 2020-07-03 07:16:16
这是我的代码的基本框架:


以下是我的代码:

package com.test;

public class Object1 {
private String s1;
private String s2;
public String getS1() {
return s1;
}
public void setS1(String s1) {
this.s1 = s1;
}
public String getS2() {
return s2;
}
public void setS2(String s2) {
this.s2 = s2;
}
}


package com.test;

public class Object2 {
private int i1;
private int i2;
public int getI1() {
return i1;
}
public void setI1(int i1) {
this.i1 = i1;
}
public int getI2() {
return i2;
}
public void setI2(int i2) {
this.i2 = i2;
}
}


package com.test;

public class Engine {
private Cache cache = new Cache();
private static Engine instance = null;

/**
* single instance mode
*/
private Engine() {

}

public Cache getCache() {
return cache;
}

public static Engine getInstance() {
synchronized (Engine.class) {
if (instance == null) {
instance = new Engine();
}
}
return instance;
}
}


package com.test;

import java.util.concurrent.locks.*;

public class HandleLock {
private String handle;
private ReentrantLock lock;

public HandleLock() {
lock = new ReentrantLock();
}

public String getHandle() {
return handle;
}
public void setHandle(String handle) {
this.handle = handle;
}
public ReentrantLock getLock() {
return lock;
}
public void setLock(ReentrantLock lock) {
this.lock = lock;
}
}


package com.test;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;

/**
* Just as the class name indicates, this is a cache.
*
*
*/
public class Cache {
/**
* map1 and map2 are used to store the actual useful information.
* The key of map1 and map2 is CacheInfo.genKey()
*/
private Map<String, Object1> map1 = new HashMap<String, Object1>();
private Map<String, Object2> map2 = new HashMap<String, Object2>();

/**
* store the CacheInfo object in this order: the first is the most recently used,
* and the last is the least recently used. For example, the first is used in 17:03,
* the second is used in 17:01, the third is used in 17:00, and so on.
* So the CacheInfo object in the end are more likely to be removed when the cache is full.
* That the cache is full means the size of the link is larger than cacheSize (the next parameter in this class).
* Every CacheInfo object in link has its information stored in map1 and map2, i.e.
* they are corresponding to each other. And so
* if link.size() is 8, map1.size() and map2.size() are both 8.
*/
private LinkedList<CacheInfo> link = new LinkedList<CacheInfo>();

int cacheSize = 10;

/**
* The key of lockMap is CacheInfo.genKey(), i.e. is the same as map1 and map2.
* Every CacheInfo object in link has its corresponding HandleLock in lockMap and of course every key
* in map1 and map2 has its corresponding HandleLock in lockMap.
*/
private HashMap<String, HandleLock> lockMap = new HashMap<String, HandleLock>();

public Object1 getObject1(String s) {
return map1.get(s);
}

public Object2 getObject2(String s) {
return map2.get(s);
}

public void removeObject1(String s) {
map1.remove(s);
}

public void removeObject2(String s) {
map2.remove(s);
}

public synchronized void removeFromLink(CacheInfo cacheInfo) {
this.link.remove(cacheInfo);
}

public synchronized boolean isExist(CacheInfo cacheInfo) {
return link.contains(cacheInfo);
}

public synchronized boolean needRemove() {
return link.size() >= cacheSize;
}

public synchronized void addToHead(CacheInfo cacheInfo) {
link.addFirst(cacheInfo);
}

public synchronized void adjustToHead(CacheInfo cacheInfo) {
CacheInfo head = link.getFirst();
if (head.equals(cacheInfo) == false) {
link.remove(cacheInfo);
link.addFirst(cacheInfo);
}
}

public synchronized HandleLock getLock(String cacheInfoKey) {
HandleLock lock = lockMap.get(cacheInfoKey);
if (lock == null) {
lock = new HandleLock();
lock.setHandle(cacheInfoKey);
lockMap.put(cacheInfoKey, lock);
}
return lock;
}

/**
* search from the end to get the first unused, i.e. the lock is not locked
* @return
*/
public synchronized CacheInfo getLastUnused() {
for (int i = link.size() - 1; i >= 0; i--) {
CacheInfo cacheInfo = link.get(i);
HandleLock lock = lockMap.get(cacheInfo.genKey());
if (lock.getLock().isLocked() == false) {
return cacheInfo;
}
}
return null;
}
}


package com.test;

/**
*
* check if the information about the current CacheInfo object is in the Cache.
* If not in Cache, load from DB.
* If in Cache, just return.
*
*/
public class CacheHandler {


public static void doCache(CacheInfo cacheInfo) {

Cache cache = Engine.getInstance().getCache();

boolean flag = cache.isExist(cacheInfo);
if (flag) {
cache.adjustToHead(cacheInfo);
return;
}
loadFromDB(cacheInfo);
}

private static void loadFromDB(CacheInfo cacheInfo) {
Cache cache = Engine.getInstance().getCache();

// to check if the cache is full, if is full, circularly remove the unused information from the cache
synchronized (cache) {
boolean needRemove = cache.needRemove();
while (needRemove) {
CacheInfo removeCacheInfo = cache.getLastUnused();
if (removeCacheInfo != null) {
HandleLock removeLock = cache.getLock(removeCacheInfo.genKey());
// lock to make sure the removeCacheInfo is not currently used by some object in Reader
removeLock.getLock().lock();
try {
// remove information about removeCacheInfo in cache
cache.removeFromLink(removeCacheInfo);
cache.removeObject1(removeCacheInfo.genKey());
cache.removeObject2(removeCacheInfo.genKey());
} finally {
removeLock.getLock().unlock();
}
} else {
break;
}

needRemove = cache.needRemove();
}
}

// read from DB about the information of cacheInfo, and put them into cache, omit this code

// if read successfully from DB
cache.addToHead(cacheInfo);
}
}


package com.test;

public class CacheInfo {
private String pkgId;
private String tmplId;

public CacheInfo(String pkgId, String tmplId) {
this.pkgId = pkgId;
this.tmplId = tmplId;
}

public String genKey() {
return pkgId + "_" + tmplId;
}

public String getPkgId() {
return pkgId;
}
public void setPkgId(String pkgId) {
this.pkgId = pkgId;
}
public String getTmplId() {
return tmplId;
}
public void setTmplId(String tmplId) {
this.tmplId = tmplId;
}

}


package com.test;

public class Reader {
public Object1 read(CacheInfo cacheInfo) {
Cache cache = Engine.getInstance().getCache();
HandleLock lock = cache.getLock(cacheInfo.genKey());
// lock so no one will remove the information about this CacheInfo object from Cache in CacheHandler
lock.getLock().lock();
try {
CacheHandler.doCache(cacheInfo);
return cache.getObject1(cacheInfo.genKey());
} finally {
lock.getLock().unlock();
}
}
}

运行我的代码的方式是跑最后的Reader类中的read函数。但是当多个用户并发去调这个函数时,由于缓存大小有限,会出现返回值为null的情况。但是我不明白,因为我在read方法中每次获取前会先lock住,然后在CacheHandler中每次删除前也会先lock住,这样按理不会出现read方法中需要读取的数据被CacheHandler中删除时删掉,因为它首先就无法lock住。请各位大侠帮我看看,我已经花了两周了,再搞不定老板要灭了我了。
...全文
3895 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

50,530

社区成员

发帖
与我相关
我的任务
社区描述
Java相关技术讨论
javaspring bootspring cloud 技术论坛(原bbs)
社区管理员
  • Java相关社区
  • 小虚竹
  • 谙忆
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧