在 Gson 里面看到一個(gè)代碼僻他,感覺(jué)寫的挺有意思的宵距。
源碼在 Gson.java 里面,用代理模式吨拗,解決了遞歸調(diào)用的問(wèn)題满哪,并且用一個(gè) ThreadLocal 變量,避免了多線程訪問(wèn)的問(wèn)題劝篷。
/**
* This thread local guards against reentrant calls to getAdapter(). In
* certain object graphs, creating an adapter for a type may recursively
* require an adapter for the same type! Without intervention, the recursive
* lookup would stack overflow. We cheat by returning a proxy type adapter.
* The proxy is wired up once the initial adapter has been created.
*/
private final ThreadLocal<Map<TypeToken<?>, FutureTypeAdapter<?>>> calls
= new ThreadLocal<Map<TypeToken<?>, FutureTypeAdapter<?>>>();
public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {
TypeAdapter<?> cached = typeTokenCache.get(type == null ? NULL_KEY_SURROGATE : type);
if (cached != null) {
return (TypeAdapter<T>) cached;
}
Map<TypeToken<?>, FutureTypeAdapter<?>> threadCalls = calls.get();
boolean requiresThreadLocalCleanup = false;
if (threadCalls == null) {
threadCalls = new HashMap<TypeToken<?>, FutureTypeAdapter<?>>();
calls.set(threadCalls);
requiresThreadLocalCleanup = true;
}
// the key and value type parameters always agree
FutureTypeAdapter<T> ongoingCall = (FutureTypeAdapter<T>) threadCalls.get(type);
if (ongoingCall != null) {
return ongoingCall;
}
try {
FutureTypeAdapter<T> call = new FutureTypeAdapter<T>();
threadCalls.put(type, call);
for (TypeAdapterFactory factory : factories) {
TypeAdapter<T> candidate = factory.create(this, type);
if (candidate != null) {
call.setDelegate(candidate);
typeTokenCache.put(type, candidate);
return candidate;
}
}
throw new IllegalArgumentException("GSON cannot handle " + type);
} finally {
threadCalls.remove(type);
if (requiresThreadLocalCleanup) {
calls.remove();
}
}
}
初看的時(shí)候哨鸭,沒(méi)有明白 threadCalls 的作用。在 try 模塊中娇妓,先是 threadCalls.put(type, call);
像鸡,然后就在 finally 里面 threadCalls.remove(type);
,好像沒(méi)有什么意義哈恰。還特意用 ThreadLocal 存儲(chǔ)了一下 calls.set(threadCalls);
只估。
1. 代理模式的作用
先說(shuō)說(shuō)遞歸調(diào)用發(fā)生的地方,是在TypeAdapter<T> candidate = factory.create(this, type);
着绷,這個(gè) create() 方法里面蛔钙,也有可能會(huì)調(diào)用 getAdapter() ,沒(méi)有適當(dāng)處理的話蓬戚,就可能會(huì)無(wú)限循環(huán)下去。
所以這里定義了一個(gè)代理對(duì)象
FutureTypeAdapter<T> call = new FutureTypeAdapter<T>();
threadCalls.put(type, call);
當(dāng)遞歸調(diào)用到這里的時(shí)候宾抓,就會(huì)先返回代理對(duì)象子漩。
FutureTypeAdapter<T> ongoingCall = (FutureTypeAdapter<T>) threadCalls.get(type);
if (ongoingCall != null) {
return ongoingCall;
}
而當(dāng)真正找到正確的 TypeAdapter<T> candidate = factory.create(this, type);
,會(huì)調(diào)用call.setDelegate(candidate);
石洗〈逼茫可以看 FutureTypeAdapter 的實(shí)現(xiàn),就是簡(jiǎn)單做一下代理讲衫。
2. ThreadLocal 的作用
getAdapter() 是 Gson 類的方法缕棵,理論上存在多線程的可能孵班。
處理多線程,通常是加鎖招驴,但是這里用 ThreadLocal<Map<TypeToken<?>, FutureTypeAdapter<?>>> calls
存儲(chǔ)threadCalls篙程,然后在 finally 里面及時(shí)清除。比加鎖要高效别厘。