另一鲜为人知的单例写法-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相关推荐

  1. 单例设计模式-ThreadLocal线程单例

    package com.learn.design.pattern.creational.singleton;/*** 是基于ThreadLocal的* 所以必不可少要使用这个类* * 我们看一下这个类 ...

  2. iOS严谨单例写法/可继承单例

    单例模式在iOS开发中可能算是最常用的模式之一了,但是由于OC本身的语言特性,想要写一个正确的单例模式相对来说比较麻烦. 今天就来说一说, 单例创建的方式和严谨的单例写法及可继承单例编写. 基本单例的 ...

  3. java单例弊端,博客大牛总结的Java单例写法的优缺点及使用场景

    在java中,单例有很多种写法,面试时,手写代码环节,除了写算法题,有时候也会让手写单例模式,这里记录一下单例的几种写法和优缺点. 为什么使用单例 1.在内存中只有一个对象,节省内存空间.避免频繁的创 ...

  4. java 单例写法_java 单例模式的几种写法

    一.懒汉式 public classSingleton{private static Singleton instance = null;privateSingleton(){}public stat ...

  5. 没想到,错误的单例写法,让 RabbitMQ 大量超时导致程序挂死!

    一:背景 1. 讲故事 10月份星球里的一位老朋友找到我,说他们公司的程序在一个网红直播带货下给弄得无响应了,无响应期间有大量的 RabbitMQ 超时,寻求如何找到根源,聊天截图我就不发了. 既然无 ...

  6. filter java 是单例的吗_JAVA 设计模式之 单例模式详解

    单例模式:(Singleton Pattern)是指确保一个类在任何情况下都绝对只有一个实例,并提供一个全局访问点.单例模式是创建型模式.单例模式在现实生活中应用也非常广泛. 在 J2EE 标准中,S ...

  7. 单例设计模式详解。。。。。。。。。。。

    public class Demo01 { public static void main(String[] args) { // TODO Auto-generated method stub /* ...

  8. @Singleton能保证单例吗

    scope里有个@Singleton,它能保证单例吗? 答案是不完全能(或者是说是有条件的能) 当你不使用@Singleton时,在同一个宿主类里,注入两次同一个类的对象你会发现,两个对象的地址不一样 ...

  9. 游戏设计模式——C++单例类

    前言: 本文将探讨单例类设计模式,单例类的懒汉模式/饿汉模式,单例类的多线程安全性,最后将利用C++模板减少单例类代码量. 本文假设有一个Manager管理类,并以此为探究单例类的设计模式. 懒汉模式 ...

最新文章

  1. 正则表达式简介及在C++11中的简单使用
  2. 等差数列末项_等差数列末项(第n项)公式
  3. Hyper-V 3.0实用技巧:创建虚拟机组快照
  4. 如何在bash脚本中提示用户进行确认? [重复]
  5. mysql查询根据季度查询_Mysql 按年、季度、月查询统计
  6. 避免App沦为“僵尸”的12个秘诀
  7. 使用脚本编写 Vim 编辑器,第 4 部分: 字典
  8. matlab版本之间的单双引号问题
  9. 用set和shopt设置bash选项
  10. winpcap基本原理及常见应用_数字图像处理原理及应用教学大纲
  11. maven 插件之maven-enforcer-plugin的使用
  12. c语言dfs算法全排列代码,c语言dfs解决全排列问题
  13. NOI图论算法:网络流
  14. 安装pkgconfig_一个R包怎么也安装不上,憋着急!
  15. html中多个div分开排列,CSS+DIV设计实例:多个DIV排列时居中
  16. CCNA学习指南第十章
  17. Verilog——38译码器(包括仿真文件和约束文件的格式)
  18. dell 恢复介质_戴尔介质恢复选项
  19. 如何在CentOS 7上安装Elasticsearch,Logstash和Kibana(ELK堆栈)
  20. 《区块链基础知识25讲》-第七讲-双花问题

热门文章

  1. UA MATH563 概率论的数学基础1 概率空间2 可列状态空间
  2. UA MATH566 统计理论 Cramer-Rao不等式与Delta方法的联系
  3. UA MATH566 统计理论7: Multiple Test
  4. Bochs调试Linux内核6 - 启动过程调试 - 跳到bootsect引导程序执行
  5. 初次使用VS附加到进程功能
  6. Matlab冒号操作符图解
  7. 并发编程之Synchronized原理
  8. Android上下左右滑动,显示底层布局
  9. autocad.net中ResultBuffer相关的常量值
  10. html贪吃蛇自动走,分享一个用html5实现的贪吃蛇特效代码