另一鲜为人知的单例写法-ThreadLocal
另一鮮為人知的單例寫法-ThreadLocal
源代碼范例
當我閱讀FocusFinder和Choreographer的時候,我發現這兩類的單例實現和我們尋經常使用雙重檢查鎖非常不一樣。而是用來一個ThreadLocal。這個也能夠實現單例啊,那這個與雙重檢查鎖實現的單例有什么差別呢?
1.FocusFinder
/*** The algorithm used for finding the next focusable view in a given direction* from a view that currently has focus.*/ public class FocusFinder {private static final ThreadLocal<FocusFinder> tlFocusFinder =new ThreadLocal<FocusFinder>() {@Overrideprotected FocusFinder initialValue() {return new FocusFinder();}};/*** Get the focus finder for this thread.*/public static FocusFinder getInstance() {return tlFocusFinder.get();}// enforce thread local accessprivate FocusFinder() {} }2.Choreographer
public final class Choreographer {// Thread local storage for the choreographer.private static final ThreadLocal<Choreographer> sThreadInstance =new ThreadLocal<Choreographer>() {@Overrideprotected Choreographer initialValue() {Looper looper = Looper.myLooper();if (looper == null) {throw new IllegalStateException("The current thread must have a looper!");}return new Choreographer(looper);}};private Choreographer(Looper looper) {mLooper = looper;mHandler = new FrameHandler(looper);mDisplayEventReceiver = USE_VSYNC ?new FrameDisplayEventReceiver(looper) : null; mLastFrameTimeNanos = Long.MIN_VALUE; mFrameIntervalNanos = (long)(1000000000 / getRefreshRate()); mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1]; for (int i = 0; i <= CALLBACK_LAST; i++) { mCallbackQueues[i] = new CallbackQueue(); } } /** * Gets the choreographer for the calling thread. Must be called from * a thread that already has a {@link android.os.Looper} associated with it. * * @return The choreographer for this thread. * @throws IllegalStateException if the thread does not have a looper. */ public static Choreographer getInstance() { return sThreadInstance.get(); } }
理論分析
ThreadLocal會為每個線程提供一個獨立的變量副本,從而隔離了多個線程對數據的訪問沖突。
對于多線程資源共享的問題,同步機制採用了“以時間換空間”的方式,而ThreadLocal採用了“以空間換時間”的方式。前者僅提供一份變量,讓不同的線程排隊訪問,而后者為每個線程都提供了一份變量。因此能夠同一時候訪問而互不影響。
public class ThreadLocal{/*** Provides the initial value of this variable for the current thread.* The default implementation returns {@code null}.** @return the initial value of the variable.*/protected T initialValue() {return null;}/*** Returns the value of this variable for the current thread. If an entry* doesn't yet exist for this variable on this thread, this method will* create an entry, populating the value with the result of* {@link #initialValue()}.** @return the current value of the variable for the calling thread.*/@SuppressWarnings("unchecked")public T get() {// Optimized for the fast path.Thread currentThread = Thread.currentThread();Values values = values(currentThread);if (values != null) {Object[] table = values.table;int index = hash & values.mask;if (this.reference == table[index]) {return (T) table[index + 1];}} else {values = initializeValues(currentThread);}return (T) values.getAfterMiss(this);}/*** Gets Values instance for this thread and variable type.*/Values values(Thread current) {return current.localValues;}/*** Sets the value of this variable for the current thread. If set to* {@code null}, the value will be set to null and the underlying entry will* still be present.** @param value the new value of the variable for the caller thread.*/public void set(T value) {Thread currentThread = Thread.currentThread();Values values = values(currentThread);if (values == null) {values = initializeValues(currentThread);}values.put(this, value);}}實現步驟
//1.initialValue,創建ThreadLocal對象 //2.get(),獲取當前線程里的values //3.假設不存在則初始化一個空的values //4.假設存在,則復用values另一處經典應用
在Looper中使用ThreadLocal,使之每個Thread都有一個Looper與之相應.
public class Looper{// sThreadLocal.get() will return null unless you've called prepare().static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();/** Initialize the current thread as a looper.* This gives you a chance to create handlers that then reference* this looper, before actually starting the loop. Be sure to call* {@link #loop()} after calling this method, and end it by calling* {@link #quit()}.*/public static void prepare() {prepare(true);}private static void prepare(boolean quitAllowed) {if (sThreadLocal.get() != null) {throw new RuntimeException("Only one Looper may be created per thread");}sThreadLocal.set(new Looper(quitAllowed));} /*** Return the Looper object associated with the current thread. Returns* null if the calling thread is not associated with a Looper.*/public static @Nullable Looper myLooper() {return sThreadLocal.get();} }自己也寫
public class Manager {private static final ThreadLocal<Manager> sManager = new ThreadLocal<Manager>() {@Overrideprotected Manager initialValue() {return new Manager();}};private Manager() {}public static Manager getInstance() {return sManager.get();} }參考
- 徹底理解ThreadLocal(http://blog.csdn.net/lufeng20/article/details/24314381)
總結
以上是生活随笔為你收集整理的另一鲜为人知的单例写法-ThreadLocal的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ORA-04031:oracle无法分配
- 下一篇: hihoCoder #1195 : 高斯