还有一鲜为人知的单例写法-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
- 还有一鲜为人知的单例写法-ThreadLocal
- 鲜为人知的Titanium之单例
- 单例的写法
- 单例的写法
- 单例的写法
- 单例的写法
- Swift单例的写法
- ios 单例的写法
- swift 单例的写法
- 单例模式的写法
- 单例的完整写法
- 各种单例的写法
- 单例模式的写法
- iOS 单例的写法
- ios 单例的写法
- Swift单例的写法
- 单例模式的写法
- 单例模式的写法
- OCR字符识别
- 3.31
- [蓝桥杯] 1的个数
- JSP详解与实例
- B
- 还有一鲜为人知的单例写法-ThreadLocal
- xilinx platform studio(XPS)打开后弹出xpsgui.exe已停止工作
- 【数据结构_树_Tree_1105】交换二叉树的孩子结点
- TCP、UDP的区别及OSI与TCP/IP参考模型
- [BZOJ1782][Usaco2010 Feb]slowdown 慢慢游(dfs序+线段树)
- Python学习笔记 面向对象编程
- fopen与读写的标识r,r+,rb+,rt+,w+.....
- c++基础之语言新特性
- Java将Unix时间戳转换成指定格式日期