读书人

android threadlocal札记

发布时间: 2012-08-14 10:39:57 作者: rapoo

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对象做自己的异步处理.

?

?

?

?

??????????

?

读书人网 >Android

热点推荐