未注明的引用均为 Java 内部包
所有 setter、getter、logger 等逻辑无关代码均忽略不计
忽略了一些常见注解
org.b3log.latke.cache.local.memory.AbstractMemoryCache
import org.b3log.latke.cache.Cache;
public abstract class AbstractMemoryCache<K extends Serializable, V extends Serializable>
implements Cache<K, V> {
private long maxCount = Long.MAX_VALUE;
private long hitCount;
private long missCount;
private long putCount;
private long cachedCount;
protected final void hitCountInc() {
hitCount++;
}
protected final void missCountInc() {
missCount++;
}
protected final void putCountInc() {
putCount++;
}
protected final void cachedCountInc() {
cachedCount++;
}
protected final void cachedCountDec() {
cachedCount--;
}
public long getCachedBytes() {
// TODO: getCachedBytes
return -1;
}
public long getHitBytes() {
// TODO: getHitBytes
return -1;
}
}
- 抽象类实现接口的作用是什么?
- 为什么采用 long 类型,int 竟然不够用?
- 类声明处 K、V 的 extends 是什么意思
org.b3log.latke.cache.local.memory.LruMemoryCache
import org.b3log.latke.cache.local.util.DoubleLinkedMap;
import org.b3log.latke.logging.Level;
import org.b3log.latke.logging.Logger;
import org.b3log.latke.util.Serializer;
public final class LruMemoryCache<K extends Serializable, V extends Serializable> extends AbstractMemoryCache<K, V> implements Serializable {
private DoubleLinkedMap<K, byte[]> map;
public LruMemoryCache() {
map = new DoubleLinkedMap<K, byte[]>();
}
public void put(final K key, final V value) {
//删除掉原有的,并添加到首部,即每次都将使用的放到最前面,是为LRU算法
remove(key);
putCountInc();
synchronized (this) {
if (getCachedCount() >= getMaxCount()) {
collect();
}
try {
map.addFirst(key, Serializer.serialize((Serializable) value));
} catch (final IOException e) {
return;
}
cachedCountInc();
}
}
public void putAsync(final K key, final V value) {
put(key, value);
}
public synchronized V get(final K key) {
final byte[] bytes = map.get(key);
if (bytes != null) {
hitCountInc();
map.makeFirst(key);
try {
return (V) Serializer.deserialize(bytes);
} catch (final Exception e) {
return null;
}
}
missCountInc();
return null;
}
public synchronized void remove(final K key) {
final boolean removed = map.remove(key);
if (removed) {
cachedCountDec();
}
}
public synchronized void remove(final Collection<K> keys) {
for (final K key : keys) {
remove(key);
}
}
public synchronized void collect() {
map.removeLast();
cachedCountDec();
}
public synchronized void removeAll() {
map.removeAll();
setCachedCount(0);
setMissCount(0);
setHitCount(0);
}
public boolean contains(final K key) {
return null != get(key); // XXX: performance issue
}
public long inc(final K key, final long delta) {
V ret = get(key);
if (null == ret || !(ret instanceof Long)) {
final Long v = delta;
ret = (V) v;
put(key, ret);
}
if (ret instanceof Long) {
final Long v = (Long) ret + delta;
ret = (V) v;
put(key, ret);
}
return (Long) ret;
}
}
- putCount 和 cachedCount 是什么关系?我以为 put 就是当前存放的容量,但是看代码使用 cachedCount 和 maxCount 相比的?
读 Cache 接口发现注释:putCount 是指存放次数,cachedCount 是指当前存放的数量。 - put 和 putAsync 看起来没什么区别,为何多加一个 putAsync?
- inc 方法是什么意思?作用是什么?
org.b3log.latke.cache.local.util.DoubleLinkedMap
public final class DoubleLinkedMap<K, V> implements Serializable {
private static final long serialVersionUID = 1L;
private int size = 0;
private DoubleLinkedMapNode<K, V> first;
private DoubleLinkedMapNode<K, V> last;
public synchronized boolean remove(final K key) {
final DoubleLinkedMapNode<K, V> node = getNode(key);
if (node != null) {
removeNode(node);
return true;
}
return false;
}
public synchronized V get(final K key) {
if (first == null) {
return null;
} else {
DoubleLinkedMapNode<K, V> current = first;
while (current != null) {
if (current.getKey().equals(key)) {
return current.getValue();
} else {
current = current.getNext();
}
}
}
return null;
}
public synchronized void addLast(final K key, final V value) {
final DoubleLinkedMapNode<K, V> node = new DoubleLinkedMapNode<K, V>(key, value);
addLastNode(node);
}
public synchronized void addFirst(final K key, final V value) {
if (null == key) {
throw new IllegalArgumentException("Key is null!");
}
final DoubleLinkedMapNode<K, V> node = new DoubleLinkedMapNode<K, V>(key, value);
addFirstNode(node);
}
public synchronized void makeFirst(final K key) {
final DoubleLinkedMapNode<K, V> node = getNode(key);
if (node.getPrev() == null) {
return;
}
//将当前节点的前一节点的下一节点改为当前节点的下一节点
node.getPrev().setNext(node.getNext());
if (node.getNext() == null) {
//如果当前节点是最后一个节点,则将前一节点的下一节点设置为null
last = node.getPrev();
last.setNext(null);
} else {
node.getNext().setPrev(node.getPrev());
}
first.setPrev(node);
node.setNext(first);
node.setPrev(null);
first = node;
}
public synchronized void removeAll() {
//此处似乎直观的体现了Java不用做垃圾处理,如果是C/C++,应有回收空间代码
for (DoubleLinkedMapNode<K, V> me = first; me != null;) {
if (me.getPrev() != null) {
me.setPrev(null);
}
final DoubleLinkedMapNode<K, V> next = me.getNext();
me = next;
}
first = null;
last = null;
size = 0;
}
public synchronized V removeLast() {
final DoubleLinkedMapNode<K, V> lastNode = removeLastNode();
if (null != lastNode) {
return lastNode.getValue();
}
return null;
}
public synchronized int size() {
return size;
}
private synchronized DoubleLinkedMapNode<K, V> removeLastNode() {
final DoubleLinkedMapNode<K, V> ret = last;
if (last != null) {
removeNode(last);
}
return ret;
}
private synchronized DoubleLinkedMapNode<K, V> getNode(final K key) {
//遍历
if (first == null) {
return null;
} else {
DoubleLinkedMapNode<K, V> current = first;
while (current != null) {
if (current.getKey().equals(key)) {
return current;
} else {
current = current.getNext();
}
}
}
return null;
}
private synchronized void removeNode(final DoubleLinkedMapNode<K, V> node) {
if (node.getNext() == null) {
if (node.getPrev() == null) {
//删除双链表的唯一节点
if (node == first && node == last) {
first = null;
last = null;
}
} else {
//删除尾节点
last = node.getPrev();
last.setNext(null);
node.setPrev(null);
}
} else if (node.getPrev() == null) {
//删除头节点
first = node.getNext();
first.setPrev(null);
node.setNext(null);
} else {
//删除中间的节点
node.getPrev().setNext(node.getNext());
node.getNext().setPrev(node.getPrev());
node.setPrev(null);
node.setNext(null);
}
size--;
}
private synchronized void addLastNode(final DoubleLinkedMapNode<K, V> node) {
if (first == null) {
first = node;
} else {
last.setNext(node);
node.setPrev(last);
}
last = node;
size++;
}
private synchronized void addFirstNode(final DoubleLinkedMapNode<K, V> node) {
if (last == null) {
last = node;
} else {
first.setPrev(node);
node.setNext(first);
}
first = node;
size++;
}
}
final class DoubleLinkedMapNode<K, V> implements Serializable {
private static final long serialVersionUID = -5617593667027497669L;
private V value;
private K key;
private DoubleLinkedMapNode<K, V> prev;
private DoubleLinkedMapNode<K, V> next;
DoubleLinkedMapNode(final K key, final V value) {
this.key = key;
this.value = value;
}
public K getKey() {
return key;
}
public V getValue() {
return value;
}
protected DoubleLinkedMapNode<K, V> getNext() {
return next;
}
protected void setNext(final DoubleLinkedMapNode<K, V> next) {
//传递对象其实就是传递引用,如此说来与指针颇为类似
this.next = next;
}
protected DoubleLinkedMapNode<K, V> getPrev() {
return prev;
}
protected void setPrev(final DoubleLinkedMapNode<K, V> prev) {
this.prev = prev;
}
}
- 为什么 addFirst 里判断了 key 是否为 null,而 addLast 没有?
-
node.getPrev().setNext(node.getNext());
if (node.getNext() == null) {
last = node.getPrev();
last.setNext(null);
} else {
node.getNext().setPrev(node.getPrev());
}
**这个逻辑看起来有点重复,是不是可以改为:**
```java
node.getPrev().setNext(node.getNext());
if (node.getNext() != null) {
node.getNext().setPrev(node.getPrev());
}
- removeLast 和 removeLastNode 看起来也没什么区别,用意何在?
org.b3log.latke.cache.Cache
//接口定义,在AbstractMemoryCache中均已涉及
public interface Cache<K extends Serializable, V extends Serializable> {
boolean contains(final K key);
void put(final K key, final V value);
void putAsync(final K key, final V value);
V get(final K key);
long inc(final K key, final long delta);
void remove(final K key);
void remove(final Collection<K> keys);
void removeAll();
void setMaxCount(final long maxCount);
long getMaxCount();
long getHitCount();
long getMissCount();
long getPutCount();
long getCachedCount();
long getCachedBytes();
long getHitBytes();
void collect();
}
org.b3log.latke.cache.CacheFactory
import org.b3log.latke.Latkes;
import org.b3log.latke.RuntimeEnv;
public final class CacheFactory {
private static final Map<String, Cache<String, ?>> CACHES = Collections.synchronizedMap(new HashMap<String, Cache<String, ?>>());
public static synchronized void removeAll() {
RuntimeEnv runtime = Latkes.getRuntime("cache");
if (RuntimeEnv.LOCAL == Latkes.getRuntimeEnv()) {
runtime = RuntimeEnv.LOCAL;
}
switch (runtime) {
case LOCAL:
for (final Map.Entry<String, Cache<String, ?>> entry : CACHES.entrySet()) {
final Cache<String, ?> cache = entry.getValue();
cache.removeAll();
}
break;
default:
throw new RuntimeException("Latke runs in the hell.... Please set the enviornment correctly");
}
}
public static synchronized Cache<String, ? extends Serializable> getCache(final String cacheName) {
Cache<String, ?> ret = CACHES.get(cacheName);
try {
if (null == ret) {
switch (Latkes.getRuntime("cache")) {
//通过反射获取到LruMemoryCache并得到一个实例
case LOCAL:
final Class<Cache<String, ?>> localLruCache = (Class<Cache<String, ?>>) Class.forName(
"org.b3log.latke.cache.local.memory.LruMemoryCache");
ret = localLruCache.newInstance();
break;
default:
throw new RuntimeException("Latke runs in the hell.... Please set the enviornment correctly");
}
CACHES.put(cacheName, ret);
}
} catch (final Exception e) {
throw new RuntimeException("Can not get cache: " + e.getMessage(), e);
}
return (Cache<String, Serializable>) ret;
}
private CacheFactory() {
}
}
- Collections.synchronizedMap 看起来是个挺高端的玩意儿,有待 bing
- 不太明白通过反射获取实例和直接 import 该类实例化有什么区别
- 这个 cacheFactory 看起来是在 Latke 处调用的,有待观察其调用过程
org.b3log.latke.cache.NoCache
public final class NoCache<K extends Serializable, V extends Serializable> implements Cache<K, V> {
private String name;
public NoCache(final String name) {
this.name = name;
}
public String getName() {
return name;
}
public boolean contains(final K key) {
return false;
}
}
//methods implements from Cache
- 该类继承了 Cache 接口并且所有方法均为空实现
- 这个类的用意何在?
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于