另一鲜为人知的单例写法-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>() {
@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)
另一鲜为人知的单例写法-ThreadLocal的更多相关文章
- Egret中的三种单例写法
1 普通的单例写法 as3中也是这么个写法. 缺点:每个单例类里都要写instance和getInstance. class Single{ private static instance:Singl ...
- Unity 单例写法
借鉴自:http://www.cnblogs.com/CodeCabin/p/unity_global_manager.html 实现复杂一些的全局控制,如切换游戏关卡等操作,更常用的方式是使用单例类 ...
- 设计模式课程 设计模式精讲 8-10 单例设计模式-ThreadLocal线程单例
1 课程讲解 1.1 应用场景 2 代码演练 2.1 threadLocal应用 1 课程讲解 1.1 应用场景 多线程的时候: 使用同步锁使用时间换空间的方式,(线程排队时间比较长) 而使用thre ...
- ARC模式下的单例写法
// 单例 + (id)sharedInstance { __strong static id sharedObject = nil; static dispatch_once_t onceToken ...
- swift3 单例写法
import UIKit class SingleOnce { // 单例 static let shared = SingleOnce.init() private init(){} // 其他方法 ...
- 基于单例使用ThreadLocal对多线程下数据的访问修改
package cn.lyy.thread; import java.util.Random; /** * 基于单例模式的基础上,使用ThreadLocal为每一个进入的线程生成一个实例, * 用来对 ...
- myapplication 单例写法
MyApplication extends Application private static MyApplication myApplication = null; oncreate中: @Ove ...
- C++单例写法
#define __xx(WaveClassFile::me()) class Xx : public QObject{ Q_OBJECT public: static Xx & me(); ...
- 十次艳遇单例设计模式(Singleton Pattern)
1.引言 单例设计模式(Singleton Pattern)是最简单且常见的设计模式之一,在它的核心结构中只包含一个被称为单例的特殊类.通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访 ...
随机推荐
- Mac下的Docker及Kubernetes(k8s)本地环境搭建与应用部署、管理界面kubernetes-dashboard
mac安装docker: brew cask install docker 当然也可以直接去官网下载docker的pkg文件安装 mac的docker国内镜像:网易的镜像地址:http://hub-m ...
- Netty Associated -- Channel
A nexus to a network socket or a component which is capable of I/O operations such as read, write, c ...
- ubuntu18.04+ cuda9.0+opencv3.1+caffe-ssd安装
详细Ubuntu18.04,CUDA9.0,OpenCV3.1,Tensorflow完全配置指南 问题1:使用Cmake编译opencv源码 CMake Error: The following va ...
- iOS开发-UIButton浅谈
UIButton算是最基本的一个控件了,不过有的时候用法挺多关于UIButton文字的位置,字体大小,字体的颜色 1.设置UIButton字体大小,尤其注意不要使用直接调用setFont: [self ...
- Android 第三方加固方案 对比 MD
常见的第三方加固方案官网介绍 由于安卓APP是基于Java的,所以极容易被破解,一个不经过加固的APP犹如裸奔一样,毫无防备.之前曾有新闻报道,一些专职的APP打包黑产就是专门从各种渠道找到apk,通 ...
- Centos7 Mysql 双机热备实现数据库高可用
mysql双主热备,也称主主互备,目的是mysql数据库高可用,只支持双机,原因是mysql的复制是一主多从,但一个从服务器只能有一个主服务器. 双机热备的条件是双机mysql版本必须一致. 服务器分 ...
- 用C#进行DirectX开发
DirectX 9.0 的Manage DirectX部分包括下列九个程序集. Microsoft.DirectX.AudioVideoPlayback.dll Microsoft.DirectX.D ...
- 交互软件Axure—高保真原型
在上一篇文章中跟大家分享了Axure7.0 的简介.基本操作和原型图的制作,主要是应用元件库里的原件进行界面元素的搭建,直至完成原型图,在最后给大家展示了高保真原型图效果.而在本次分享中,主要带领大家 ...
- 【Scala】Scala学习资料
Scala学习资料 java 树形 分类器_百度搜索 决策树分类器-Java实现 - CSDN博客 KNN分类器-Java实现 - CSDN博客 学习:java设计模式—分类 - 飞翔荷兰人 - 博客 ...
- 理解TensorFlow的Queue
https://www.jianshu.com/p/d063804fb272 这篇文章来说说TensorFlow里与Queue有关的概念和用法. 其实概念只有三个: Queue是TF队列和缓存机制的实 ...