android threadlocal笔记
总所周知,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对象做自己的异步处理.
?
?
?
?
??????????
?