总所周知,threadlocal用的还是蛮多的,今天回顾android源码又看到它的影子,所以自己抽空做个笔记,先从一个简单的例子开始,该例子就是让每个线程拥有自己唯一的一个Student对象,具体代码如下
package com.threadlocalttest;
/**
* 学生类
* @author Administrator
*
*/
public class Student {
private ThreadLocal threadlocal = new ThreadLocal();
public Student generateStuPerThread() {
Student stu = (Student) threadlocal.get();
if (stu == null) {
stu = new Student();
threadlocal.set(stu);
}
return stu;
}
}
package com.threadlocalttest;
/**
* 测试类
* @author Administrator
*
*/
public class TestMain {
public void begin()
{
new Thread(new WorkThread(new Student())).start();
}
public static void main(String[] args) {
new TestMain().begin();
new TestMain().begin();
}
private class WorkThread implements Runnable{
private Student stu;
public WorkThread(Student stu)
{
this.stu=stu;
}
@Override
public void run() {
try{
System.out.println(stu.generateStuPerThread()+"=============>1");
Thread.sleep(2000);
System.out.println(stu.generateStuPerThread()+"=============>2");
Thread.sleep(2000);
System.out.println(stu.generateStuPerThread()+"=============>3");
}catch(Exception e)
{
e.printStackTrace();
}
}
}
}
运行后的打印结果如下
com.threadlocalttest.Student@14318bb=============>1
com.threadlocalttest.Student@1a758cb=============>1
com.threadlocalttest.Student@14318bb=============>2
com.threadlocalttest.Student@1a758cb=============>2
com.threadlocalttest.Student@14318bb=============>3
com.threadlocalttest.Student@1a758cb=============>3
通过以上实验结果我们来分析下ThreadLocal的内部机制
下面来看看该类的实现原理
首先看看该类的官方解释
* <p>Each thread holds an implicit reference to its copy of a thread-local
* variable as long as the thread is alive and the <tt>ThreadLocal</tt>
* instance is accessible; after a thread goes away, all of its copies of
* thread-local instances are subject to garbage collection (unless other
* references to these copies exist).
大概意思不用说也明白了,只要线程存活它便拥有一个ThreadLocal引用,而且它是可访问的,一旦线程运行结束,所有的threadlocal副本就会被gc回收(除非对这些副本的其它引用还存在)
ThreadLocal类主要有三个成员变量
/**
* ThreadLocals rely on per-thread hash maps attached to each thread
* (Thread.threadLocals and inheritableThreadLocals). The ThreadLocal
* objects act as keys, searched via threadLocalHashCode. This is a
* custom hash code (useful only within ThreadLocalMaps) that eliminates
* collisions in the common case where consecutively constructed
* ThreadLocals are used by the same threads, while remaining well-behaved
* in less common cases.
*/
//threadlocal就是通过每个线程的hash maps与每个线程进行关联的,threadlocal作为key,是通过threadLocalHashCode找到的,通过使用该种方式,当多个线程连续访问threadlocals是可以避免冲突
private final int threadLocalHashCode = nextHashCode();
/**
* The next hash code to be given out. Accessed only by like-named method.
*/
private static int nextHashCode = 0;
/**
* The difference between successively generated hash codes - turns
* implicit sequential thread-local IDs into near-optimally spread
* multiplicative hash values for power-of-two-sized tables.
*/
private static final int HASH_INCREMENT = 0x61c88647;
在看看该类的两大重要方法
首先是set方法
/**
* Sets the current thread's copy of this thread-local variable
* to the specified value. Many applications will have no need for
* this functionality, relying solely on the {@link #initialValue}
* method to set the values of thread-locals.
*
* @param value the value to be stored in the current threads' copy of
* this thread-local.
*/
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
通过该方法将threadlocal对象与用户想要保存在线程里面的对象绑定,(ThreadLocalMap 是ThreadLocal的嵌套类,通过该类的set方法,将threadlocal对象与保存的对象进行绑定
/**
* Set the value associated with key.
*
* @param key the thread local object
* @param value the value to be set
*/
private void set(ThreadLocal key, Object value) {
// We don't use a fast path as with get() because it is at
// least as common to use set() to create new entries as
// it is to replace existing ones, in which case, a fast
// path would fail more often than not.
Entry[] tab = table;
int len = tab.length;
int i = key.threadLocalHashCode & (len-1);
for (Entry e = tab[i];
e != null;
e = tab[i = nextIndex(i, len)]) {
ThreadLocal k = e.get();
if (k == key) {
e.value = value;
return;
}
if (k == null) {
replaceStaleEntry(key, value, i, false);
return;
}
}
//将threadlocal的threadLocalHashCode作为entry数组的下标,并生成一个entry条目,并用下标指向
tab[i] = new Entry(key, value);
int sz = ++size;
if (!cleanSomeSlots(i, sz) && sz >= threshold)
rehash();
}
ThreadLocalMap 类内部内部嵌套类entry的声明如下
private static class Entry extends WeakReference<ThreadLocal> {
/** The value associated with this ThreadLocal. */
private Object value;
private Entry(ThreadLocal k, Object v) {
super(k);
value = v;
}
}
然后是get方法
/**
* Returns the value in the current thread's copy of this thread-local
* variable. Creates and initializes the copy if this is the first time
* the thread has called this method.
*
* @return the current thread's value of this thread-local
*/
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
return (T)map.get(this);
// Maps are constructed lazily. if the map for this thread
// doesn't exist, create it, with this ThreadLocal and its
// initial value as its only entry.
T value = initialValue();
createMap(t, value);
return value;
}
通过该方法获取该线程的绑定对象,具体的实现与set刚好相反
通过以上的表述,总结下threadLocalHashCode,ThreadLocal,value的关系是,
存储方式 (entry的索引)threadLocalHashCode (ThreadLocal,value)(entry条目)
(entry的索引)threadLocalHashCode (ThreadLocal,value)(entry条目)
(entry的索引)threadLocalHashCode (ThreadLocal,value)(entry条目)
..........................................................................................................
其实就是维持了这样一个entry数组
threadlocal在很多框架用到,向struts2的actioncontext,hibernate的session等,
下面来说说android里面threadlocal的一个典型应用,其实就是Looper,Looper主要就是用来做异步操作的,为一个线程来不断的遍历一个消息对象队列,很显然每个Looper对象要和特定的线程做单一绑定,很显然会使用threadlocal,
下面来从一个简单的例子分析下该类内部具体对threadlocal的使用,引用该类内部提供的一个demo,代码如下
* class LooperThread extends Thread {
* public Handler mHandler;
*
* public void run() {
* Looper.prepare();
*
* mHandler = new Handler() {
* public void handleMessage(Message msg) {
* // process incoming messages here
* }
* };
* //死循环,遍历消息队列,并作回调操作
* Looper.loop();
* }
* }
既然用到threadlocal,即Looper内部必有一个threadlocal变量
打开Looper类,确实该类内部有threadlocal变量
private static final ThreadLocal sThreadLocal = new ThreadLocal();
在看看该类的prepare 方法
public static final void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
threadlocal很熟悉的使用方式,通过该种方式,线程可以方便的使用Looper对象做自己的异步处理.
分享到:
相关推荐
### Android 安卓笔记知识点详解 #### Android—基础 ##### 基础—概念 - **控件类之父**:`View`是所有控件的基类,无论是简单的按钮还是复杂的列表视图,都是从这个类派生出来的。 - **基准线**:在英文书写中,...
Java线程技术是软件工程领域不可或缺的一部分,尤其在底层编程、Android应用开发以及游戏开发中,其重要性不言而喻。然而,尽管Java程序员普遍了解线程的基础概念,但在项目实践中,尤其是在复杂场景下处理多线程...
通过张龙老师的Java SE课堂笔记,学习者不仅可以理解Java语言的基本语法,还能掌握面向对象设计原则和实战技巧,为后续的Java EE(企业版)和Android开发打下坚实的基础。同时,笔记中的实例和练习将帮助巩固理论...
Java广泛应用于服务器端开发、移动应用(尤其是Android平台)、大数据处理、云计算等领域。它的主要特点包括跨平台性(Write Once, Run Anywhere,WORA)、垃圾回收机制、丰富的类库以及强大的社区支持。 【压缩...
python学习资源
jfinal-undertow 用于开发、部署由 jfinal 开发的 web 项目
基于Andorid的音乐播放器项目设计(国外开源)实现源码,主要针对计算机相关专业的正在做毕设的学生和需要项目实战练习的学习者,也可作为课程设计、期末大作业。
python学习资源
python学习资源
python学习一些项目和资源
【毕业设计】java-springboot+vue家具销售平台实现源码(完整前后端+mysql+说明文档+LunW).zip
HTML+CSS+JavaScarip开发的前端网页源代码
python学习资源
【毕业设计】java-springboot-vue健身房信息管理系统源码(完整前后端+mysql+说明文档+LunW).zip
成绩管理系统C/Go。大学生期末小作业,指针实现,C语言版本(ANSI C)和Go语言版本
1_基于大数据的智能菜品个性化推荐与点餐系统的设计与实现.docx
【毕业设计】java-springboot-vue交流互动平台实现源码(完整前后端+mysql+说明文档+LunW).zip
内容概要:本文主要探讨了在高并发情况下如何设计并优化火车票秒杀系统,确保系统的高性能与稳定性。通过对比分析三种库存管理模式(下单减库存、支付减库存、预扣库存),强调了预扣库存结合本地缓存及远程Redis统一库存的优势,同时介绍了如何利用Nginx的加权轮询策略、MQ消息队列异步处理等方式降低系统压力,保障交易完整性和数据一致性,防止超卖现象。 适用人群:具有一定互联网应用开发经验的研发人员和技术管理人员。 使用场景及目标:适用于电商、票务等行业需要处理大量瞬时并发请求的业务场景。其目标在于通过合理的架构规划,实现在高峰期保持平台的稳定运行,保证用户体验的同时最大化销售额。 其他说明:文中提及的技术细节如Epoll I/O多路复用模型以及分布式系统中的容错措施等内容,对于深入理解大规模并发系统的构建有着重要指导意义。
基于 OpenCV 和 PyTorch 的深度车牌识别
【毕业设计-java】springboot-vue教学资料管理系统实现源码(完整前后端+mysql+说明文档+LunW).zip