还有一鲜为人知的单例写法-ThreadLocal

来源:互联网 发布:少儿编程 比尔盖茨 编辑:程序博客网 时间:2024/06/06 00:43

还有一鲜为人知的单例写法-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>() {                @Override                protected FocusFinder initialValue() {                    return new FocusFinder();                }            };    /**     * Get the focus finder for this thread.     */    public static FocusFinder getInstance() {        return tlFocusFinder.get();    }    // enforce thread local access    private FocusFinder() {}}

2.Choreographer

public final class Choreographer {    // Thread local storage for the choreographer.    private static final ThreadLocal<Choreographer> sThreadInstance =            new ThreadLocal<Choreographer>() {        @Override        protected 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>() {        @Override        protected Manager initialValue() {            return new Manager();        }    };    private Manager() {    }    public static Manager getInstance() {        return sManager.get();    }}

参考

  • 彻底理解ThreadLocal(http://blog.csdn.net/lufeng20/article/details/24314381)
3 0
原创粉丝点击