前言
月是一轮明镜,晶莹剔透,代表着一张白纸(啥也不懂)
央是一片海洋,海乃百川,代表着一块海绵(吸纳万物)
泽是一柄利剑,千锤百炼,代表着千百锤炼(输入输出)
月央泽,学习的一种过程,从白纸->吸收各种知识->不断输入输出变成自己的内容
希望大家一起坚持这个过程,也同样希望大家最终都能从零到零,把知识从薄变厚,再由厚变薄!
一.ClassValue的作用:
直接看源码注释(我的翻译可能不太准,如果道友们有更棒的理解,可以留言或者私信)
/**
* Lazily associate a computed value with (potentially) every type.
* For example, if a dynamic language needs to construct a message dispatch
* table for each class encountered at a message send call site,
* it can use a {@code ClassValue} to cache information needed to
* perform the message send quickly, for each class encountered.
* 延迟地将计算值与(可能)每种类型相关联。
* 例如,如果动态语言需要为在消息发送调用站点遇到的每个类构建一个消息调度表,
* 它可以使用 ClassValue来缓存为遇到的每个类快速执行消息发送所需的信息。
* @author John Rose, JSR 292 EG
* @since 1.7
*/
二.成员变量:
/** Initial, one-element, empty cache used by all Class instances. Must never be filled. */
//所有 Class 实例使用的初始、单元素、空缓存。绝对不能填满
private static final Entry<?>[] EMPTY_CACHE = { null };
//用于访问 Class.classValueMap.cacheArray 的内部哈希码。
final int hashCodeForCache = nextHashCode.getAndAdd(HASH_INCREMENT) & HASH_MASK;
//hashCodeForCache 的值流。请参阅 ThreadLocal 中的类似结构
private static final AtomicInteger nextHashCode = new AtomicInteger();
//适用于 2 的幂表。请参阅 ThreadLocal 中的类似结构
private static final int HASH_INCREMENT = 0x61c88647;
//将哈希码屏蔽为正数但不要太大,以防止回绕。
static final int HASH_MASK = (-1 >>> 2);
/**
* //这个 ClassValue 的标识,表示为一个不透明的对象。
* 主对象 ClassValue.this不正确,因为子类可能会覆盖 ClassValue.equals,
* 这可能会混淆 ClassValueMap 中的键
*/
final Identity identity = new Identity();
//避免死锁的私有对象
private static final Object CRITICAL_SECTION = new Object();
//判断当前对象的版本
private volatile Version<T> version = new Version<>(this);
三.内部类:
Identity
/**
* Private key for retrieval of this object from ClassValueMap.
* //用于从 ClassValueMap 检索此对象的私钥
*/
static class Identity {
}
Version
static class Version<T> {
private final ClassValue<T> classValue;
private final Entry<T> promise = new Entry<>(this);
Version(ClassValue<T> classValue) { this.classValue = classValue; }
ClassValue<T> classValue() { return classValue; }
Entry<T> promise() { return promise; }
boolean isLive() { return classValue.version() == this; }
}
Entry
/** One binding of a value to a class via a ClassValue.
* 1.通过 ClassValue 将一个值绑定到一个类。
* 2.状态是:
* 允许时value = Entry.this
* 死亡时value= null
* 陈旧时version!=classValueversion
* 否则就是活跃状态
* Promises 永远不会放入缓存;它们只存在于支持映射中,而计算值调用正在进行中。
* 一旦条目变得陈旧,它可以随时重置为死状态
*/
static class Entry<T> extends WeakReference<Version<T>> {
//通常是 T 型,但有时 (Entry)this
final Object value; // usually of type T, but sometimes (Entry)this
Entry(Version<T> version, T value) {
super(version);
//对于常规条目,值的类型为 T
this.value = value; // for a regular entry, value is of type T
}
private void assertNotPromise() { assert(!isPromise()); }
/** For creating a promise. */
//promise状态
Entry(Version<T> version) {
super(version);
this.value = this; // for a promise, value is not of type T, but Entry!
}
/** Fetch the value. This entry must not be a promise. */
//取值。此条目不能是Promise
@SuppressWarnings("unchecked") // if !isPromise, type is T
T value() { assertNotPromise(); return (T) value; }
boolean isPromise() { return value == this; }
Version<T> version() { return get(); }
ClassValue<T> classValueOrNull() {
Version<T> v = version();
return (v == null) ? null : v.classValue();
}
boolean isLive() {
Version<T> v = version();
if (v == null) return false;
if (v.isLive()) return true;
clear();
return false;
}
Entry<T> refreshVersion(Version<T> v2) {
assertNotPromise();
@SuppressWarnings("unchecked") // if !isPromise, type is T
Entry<T> e2 = new Entry<>(v2, (T) value);
clear();
// value = null -- caller must drop
return e2;
}
//dead状态
static final Entry<?> DEAD_ENTRY = new Entry<>(null, null);
}
ClassValueMap
/** A backing map for all ClassValues, relative a single given type.
* 所有 ClassValues 的支持映射,相对于单个给定类型。为
* 每对(ClassValue cv,Class 类型)提供一个完全序列化的“真实状态”。还管理未序列化的快速路径缓存
*/
static class ClassValueMap extends WeakHashMap<ClassValue.Identity, Entry<?>> {
private final Class<?> type;
private Entry<?>[] cacheArray;
private int cacheLoad, cacheLoadLimit;
/**
* 首次与任何 ClassValue 一起使用时,最初分配给每种类型的条目数。
* 使它比 Class 和 ClassValueMap 对象本身小得多是没有意义的。必须是 2 的幂
*/
private static final int INITIAL_ENTRIES = 32;
/**
* 为 ClassValues 构建一个支持映射,相对于给定的类型。
* 此外,创建一个空的缓存数组并将其安装在类上
*/
ClassValueMap(Class<?> type) {
this.type = type;
sizeCache(INITIAL_ENTRIES);
}
Entry<?>[] getCache() { return cacheArray; }
//发起查询。如果还没有值,则存储promise(占位符)
synchronized
<T> Entry<T> startEntry(ClassValue<T> classValue) {
@SuppressWarnings("unchecked") // one map has entries for all value types <T>
Entry<T> e = (Entry<T>) get(classValue.identity);
Version<T> v = classValue.version();
if (e == null) {
e = v.promise();
//promise的存在意味着 v 的值正在等待。最终,finishEntry 将覆盖promise
put(classValue.identity, e);
// Note that the promise is never entered into the cache!
//请注意,promise永远不会进入缓存
return e;
} else if (e.isPromise()) {
// Somebody else has asked the same question.
// Let the races begin!
if (e.version() != v) {
e = v.promise();
put(classValue.identity, e);
}
return e;
} else {
// there is already a completed entry here; report it
//这里已经有一个完整的条目;举报
if (e.version() != v) {
//这里有一个陈旧但有效的条目;让它再次新鲜。
// 一旦一个条目在哈希表中,我们就不关心它的版本是什么
e = e.refreshVersion(v);
put(classValue.identity, e);
}
// Add to the cache, to enable the fast path, next time.
//添加到缓存中,下次以启用快速路径,
checkCacheLoad();
addToCache(classValue, e);
return e;
}
}
synchronized
<T> Entry<T> finishEntry(ClassValue<T> classValue, Entry<T> e) {
@SuppressWarnings("unchecked") // one map has entries for all value types <T>
Entry<T> e0 = (Entry<T>) get(classValue.identity);
if (e == e0) {
// We can get here during exception processing, unwinding from computeValue.
assert(e.isPromise());
remove(classValue.identity);
return null;
} else if (e0 != null && e0.isPromise() && e0.version() == e.version()) {
// If e0 matches the intended entry, there has not been a remove call
// between the previous startEntry and now. So now overwrite e0.
Version<T> v = classValue.version();
if (e.version() != v)
e = e.refreshVersion(v);
put(classValue.identity, e);
// Add to the cache, to enable the fast path, next time.
checkCacheLoad();
addToCache(classValue, e);
return e;
} else {
// Some sort of mismatch; caller must try again.
return null;
}
}
/** Remove an entry. */
synchronized
void removeEntry(ClassValue<?> classValue) {
Entry<?> e = remove(classValue.identity);
if (e == null) {
// Uninitialized, and no pending calls to computeValue. No change.
} else if (e.isPromise()) {
// State is uninitialized, with a pending call to finishEntry.
// Since remove is a no-op in such a state, keep the promise
// by putting it back into the map.
put(classValue.identity, e);
} else {
// In an initialized state. Bump forward, and de-initialize.
classValue.bumpVersion();
// Make all cache elements for this guy go stale.
removeStaleEntries(classValue);
}
}
/** Change the value for an entry. */
synchronized
<T> void changeEntry(ClassValue<T> classValue, T value) {
@SuppressWarnings("unchecked") // one map has entries for all value types <T>
Entry<T> e0 = (Entry<T>) get(classValue.identity);
Version<T> version = classValue.version();
if (e0 != null) {
if (e0.version() == version && e0.value() == value)
// no value change => no version change needed
return;
classValue.bumpVersion();
removeStaleEntries(classValue);
}
Entry<T> e = makeEntry(version, value);
put(classValue.identity, e);
// Add to the cache, to enable the fast path, next time.
checkCacheLoad();
addToCache(classValue, e);
}
static Entry<?> loadFromCache(Entry<?>[] cache, int i) {
// non-racing cache.length : constant
// racing cache[i & (mask)] : null <=> Entry
return cache[i & (cache.length-1)];
// invariant: returned value is null or well-constructed (ready to match)
}
/** Look in the cache, at the home location for the given ClassValue. */
static <T> Entry<T> probeHomeLocation(Entry<?>[] cache, ClassValue<T> classValue) {
return classValue.castEntry(loadFromCache(cache, classValue.hashCodeForCache));
}
/** Given that first probe was a collision, retry at nearby locations. */
static <T> Entry<T> probeBackupLocations(Entry<?>[] cache, ClassValue<T> classValue) {
if (PROBE_LIMIT <= 0) return null;
// Probe the cache carefully, in a range of slots.
int mask = (cache.length-1);
int home = (classValue.hashCodeForCache & mask);
Entry<?> e2 = cache[home]; // victim, if we find the real guy
if (e2 == null) {
return null; // if nobody is at home, no need to search nearby
}
// assume !classValue.match(e2), but do not assert, because of races
int pos2 = -1;
for (int i = home + 1; i < home + PROBE_LIMIT; i++) {
Entry<?> e = cache[i & mask];
if (e == null) {
break; // only search within non-null runs
}
if (classValue.match(e)) {
// relocate colliding entry e2 (from cache[home]) to first empty slot
cache[home] = e;
if (pos2 >= 0) {
cache[i & mask] = Entry.DEAD_ENTRY;
} else {
pos2 = i;
}
cache[pos2 & mask] = ((entryDislocation(cache, pos2, e2) < PROBE_LIMIT)
? e2 // put e2 here if it fits
: Entry.DEAD_ENTRY);
return classValue.castEntry(e);
}
// Remember first empty slot, if any:
if (!e.isLive() && pos2 < 0) pos2 = i;
}
return null;
}
/** How far out of place is e? */
//e 离位多远?
private static int entryDislocation(Entry<?>[] cache, int pos, Entry<?> e) {
ClassValue<?> cv = e.classValueOrNull();
if (cv == null) return 0; // entry is not live!
int mask = (cache.length-1);
return (pos - cv.hashCodeForCache) & mask;
}
private void sizeCache(int length) {
assert((length & (length-1)) == 0); // must be power of 2
cacheLoad = 0;
cacheLoadLimit = (int) ((double) length * CACHE_LOAD_LIMIT / 100);
cacheArray = new Entry<?>[length];
}
/** Make sure the cache load stays below its limit, if possible. */
//如果可能,请确保缓存负载保持在其限制以下
private void checkCacheLoad() {
if (cacheLoad >= cacheLoadLimit) {
reduceCacheLoad();
}
}
private void reduceCacheLoad() {
removeStaleEntries();
if (cacheLoad < cacheLoadLimit)
return; // win
Entry<?>[] oldCache = getCache();
if (oldCache.length > HASH_MASK)
return; // lose
sizeCache(oldCache.length * 2);
for (Entry<?> e : oldCache) {
if (e != null && e.isLive()) {
addToCache(e);
}
}
}
/**
* 删除给定范围内的陈旧条目。应该在地图锁下执行
*/
private void removeStaleEntries(Entry<?>[] cache, int begin, int count) {
if (PROBE_LIMIT <= 0) return;
int mask = (cache.length-1);
int removed = 0;
for (int i = begin; i < begin + count; i++) {
Entry<?> e = cache[i & mask];
if (e == null || e.isLive())
continue; // skip null and live entries
Entry<?> replacement = null;
if (PROBE_LIMIT > 1) {
// avoid breaking up a non-null run
//避免中断非空运行
replacement = findReplacement(cache, i);
}
cache[i & mask] = replacement;
if (replacement == null) removed += 1;
}
cacheLoad = Math.max(0, cacheLoad - removed);
}
/**
* 清除缓存槽有可能将后续条目与非空运行的头部断开连接,
* 这将允许通过重新探测找到它们。在 cache[begin] 之后查找一个条目以插入该漏洞,如果不需要则返回 null
*/
private Entry<?> findReplacement(Entry<?>[] cache, int home1) {
Entry<?> replacement = null;
int haveReplacement = -1, replacementPos = 0;
int mask = (cache.length-1);
for (int i2 = home1 + 1; i2 < home1 + PROBE_LIMIT; i2++) {
Entry<?> e2 = cache[i2 & mask];
if (e2 == null) break; // End of non-null run.
if (!e2.isLive()) continue; // Doomed anyway.
int dis2 = entryDislocation(cache, i2, e2);
if (dis2 == 0) continue; // e2 already optimally placed
int home2 = i2 - dis2;
if (home2 <= home1) {
// e2 can replace entry at cache[home1]
if (home2 == home1) {
// Put e2 exactly where he belongs.
haveReplacement = 1;
replacementPos = i2;
replacement = e2;
} else if (haveReplacement <= 0) {
haveReplacement = 0;
replacementPos = i2;
replacement = e2;
}
// And keep going, so we can favor larger dislocations.
}
}
if (haveReplacement >= 0) {
if (cache[(replacementPos+1) & mask] != null) {
// Be conservative, to avoid breaking up a non-null run.
cache[replacementPos & mask] = (Entry<?>) Entry.DEAD_ENTRY;
} else {
cache[replacementPos & mask] = null;
cacheLoad -= 1;
}
}
return replacement;
}
//删除 classValue 附近范围内的陈旧条目
private void removeStaleEntries(ClassValue<?> classValue) {
removeStaleEntries(getCache(), classValue.hashCodeForCache, PROBE_LIMIT);
}
//删除所有陈旧条目,无处不在
private void removeStaleEntries() {
Entry<?>[] cache = getCache();
removeStaleEntries(cache, 0, cache.length + PROBE_LIMIT - 1);
}
//将给定条目添加到缓存中,在其主位置,除非它已过期
private <T> void addToCache(Entry<T> e) {
ClassValue<T> classValue = e.classValueOrNull();
if (classValue != null)
addToCache(classValue, e);
}
//将给定的条目添加到缓存中,在其主位置
private <T> void addToCache(ClassValue<T> classValue, Entry<T> e) {
if (PROBE_LIMIT <= 0) return; // do not fill cache
// Add e to the cache.
Entry<?>[] cache = getCache();
int mask = (cache.length-1);
int home = classValue.hashCodeForCache & mask;
Entry<?> e2 = placeInCache(cache, home, e, false);
if (e2 == null) return; // done
if (PROBE_LIMIT > 1) {
// try to move e2 somewhere else in his probe range
int dis2 = entryDislocation(cache, home, e2);
int home2 = home - dis2;
for (int i2 = home2; i2 < home2 + PROBE_LIMIT; i2++) {
if (placeInCache(cache, i2 & mask, e2, true) == null) {
return;
}
}
}
// Note: At this point, e2 is just dropped from the cache.
}
/**
* 存储给定的条目。更新 cacheLoad,并返回任何活着的受害者。 “轻轻”意味着回归自我,而不是让一个活生生的受害者脱臼
*/
private Entry<?> placeInCache(Entry<?>[] cache, int pos, Entry<?> e, boolean gently) {
Entry<?> e2 = overwrittenEntry(cache[pos]);
if (gently && e2 != null) {
// do not overwrite a live entry
return e;
} else {
cache[pos] = e;
return e2;
}
}
/**
* 请注意即将被覆盖的条目。如果它不是活的,则悄悄地将其替换为空值。
* 如果它是一个实际的空值,增加 cacheLoad,因为调用者将在它的位置存储一些东西
*/
private <T> Entry<T> overwrittenEntry(Entry<T> e2) {
if (e2 == null) cacheLoad += 1;
else if (e2.isLive()) return e2;
return null;
}
/** Percent loading of cache before resize. */
//调整大小前缓存的加载百分比
private static final int CACHE_LOAD_LIMIT = 67; // 0..100
/** Maximum number of probes to attempt. */
//尝试的最大探测数
private static final int PROBE_LIMIT = 6; // 1..
}
四.构造方法:
/**
* Sole constructor. (For invocation by subclass constructors, typically
* implicit.)
* 唯一的构造函数。 (对于子类构造函数的调用,通常是隐式的。)
*/
protected ClassValue() {
}
五.内部方法:
computeValue
/**
* 1.计算此 {@code ClassValue} 的给定类的派生值
* 2.此方法将在使用 get 方法访问该值的第一个线程中调用
* 3.通常,每个类最多调用一次此方法,但如果已调用 remove,则可能会再次调用它
* 4.如果此方法抛出异常,相应的get调用将因该异常异常终止,并且不会记录任何类值
*/
protected abstract T computeValue(Class<?> type);
get()
/**
* 1.返回给定类的值。如果尚未计算任何值,则通过调用computeValue方法获得
* 2.类上值的实际安装是原子执行的。
* 3.在这一点上,如果多个竞速线程有计算值,则选择一个,并将其返回给所有竞速线程
* 4.参数通常是一个类,但它可以是任何类型,例如接口、原始类型(如 int.class)或void.class
* 5.type参数通常是一个类,但它可以是任何类型,例如接口、原始类型(如 int.class或 void.class
*/
public T get(Class<?> type) {
Entry<?>[] cache;
Entry<T> e = probeHomeLocation(cache = getCacheCarefully(type), this);
//当前值 <=> 来自当前缓存或陈旧缓存的陈旧值
//e 为 null 或具有可读 Entry.version 和 Entry.value 的条目
if (match(e))
return e.value();
//快速路径可能因以下任何原因而失败:
// 1. 尚未计算任何条目
// 2. 哈希码冲突(减少 mod cache.length 之前或之后)
// 3. 条目已被删除(在此类型或其他类型上)
// 4 . GC 以某种方式设法删除了 e.version 并清除了引用
return getFromBackup(cache, type);
}
remove()
/**
* 1.删除给定类的关联值。如果此值随后为同一类 get/read,
* 则其值将通过调用其 computeValue 方法重新初始化。
* 这可能会导致对给定类的computeValue方法的额外调用
* 2.为了解释 get和 remove调用之间的交互,我们必须对类值的状态转换进行建模,
* 以考虑未初始化和初始化状态之间的交替。为此,请从零开始对这些状态进行顺序编号,
* 并注意未初始化(或删除)状态使用偶数编号,而初始化(或重新初始化)状态使用奇数编号
* 3.当线程 T在状态 2N中删除类值时,什么也不会发生,因为类值已经未初始化。
* 否则,状态将自动推进到2N+1
* 4.当线程T查询状态2N的类值时,该线程首先尝试通过调用computeValue并安装结果值来将类值初始化为状态2N+1
* 5.当 T尝试安装新计算的值时,如果状态仍为2N,则类值将使用计算值进行初始化,将其推进到状态2N+1
* 6.否则,无论新状态是偶数还是奇数,T都会丢弃新计算的值并重试 get 操作
* 7.丢弃和重试是一个重要的条件,否则 T可能会安装一个灾难性的陈旧值
* 8.我们可以假设在上面的场景中CV.computeValue在计算 V1等时使用锁来正确观察依赖于时间的状态。
* 这并没有消除过时值的威胁,因为有在 T中返回 computeValue和安装新值之间的时间窗口。在此期间无法进行用户同步
*/
public void remove(Class<?> type) {
ClassValueMap map = getMap(type);
map.removeEntry(this);
}
match
//检查 e 是否为非空、是否与此 ClassValue 匹配且是否有效
boolean match(Entry<?> e) {
return (e != null && e.get() == this.version);
}
六.总结:
mark一下,看未来这东西有啥用....