总所周知,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对象做自己的异步处理.
分享到:
相关推荐
ThreadLocal源码(版本:Android4.3,,含注释)
ThreadLocal和InheritableThreadLocal是Java中两个非常重要的线程相关的类,它们在Android开发中也有广泛应用。本文将深入解析这两个概念以及它们在Android环境下的工作原理。 **ThreadLocal** 是一个线程局部变量...
在Android开发中,ThreadLocal是一个非常重要的工具类,它提供了线程局部变量的存储机制。ThreadLocal类允许我们在多线程环境下为每个线程维护独立的变量副本,从而避免了传统共享变量带来的线程安全问题。下面将...
Android 中 ThreadLocal 的深入理解 Android 中 ThreadLocal 的深入理解是指在 Android 开发中对 ThreadLocal 的深入理解和应用。ThreadLocal 是 Java 语言中的一种线程内部数据存储机制,通过它可以在指定的线程中...
**线程局部变量(ThreadLocal)是Java编程中一个非常重要的工具类,它在多线程环境下提供了线程安全的数据存储。ThreadLocal并不是一个变量,而是一个类,它为每个线程都创建了一个独立的变量副本,使得每个线程都...
ThreadLocal是Java编程语言中的一个类,用于在多线程环境中提供线程局部变量。它是一种特殊类型的变量,每个线程都有自己的副本,互不影响,从而实现线程间数据隔离。ThreadLocal通常被用来解决线程共享数据时可能...
在 `LeakingServlet` 的 `doGet` 方法中,如果 `ThreadLocal` 没有设置值,那么会创建一个新的 `MyCounter` 并设置到 `ThreadLocal` 中。关键在于,一旦 `MyCounter` 被设置到 `ThreadLocal`,那么它将与当前线程...
理解ThreadLocal 理解ThreadLocal 理解ThreadLocal 理解ThreadLocal
ThreadLocal 整理 ThreadLocal 是 Java 中的一个重要组件,它能够在每个线程中保持独立的副本。这个功能是通过 Thread 类中的 threadLocals 属性来实现的,这个属性实际上是一个 Entry 数组,其中的每个 Entry 都...
- `HttpClient学习笔记.doc`: 可能包含了关于Apache HttpClient的使用教程,包括如何创建HTTP请求,执行GET和POST操作,以及设置请求头和处理响应等内容。 - `HTTP中Get与Post的区别.doc`: 深入解析HTTP协议中的GET...
### 正确理解ThreadLocal:深入解析其工作原理与应用场景 #### 一、ThreadLocal的基本概念 `ThreadLocal`是Java平台提供的一种线程局部变量的解决方案,它为每一个使用该变量的线程都提供了独立的变量副本,使得每...
Java中的ThreadLocal是一个非常重要的工具类,它在多线程编程中扮演着独特角色,尤其在处理线程间数据隔离和共享时。ThreadLocal不是线程本身,而是为每个线程提供一个独立的变量副本,使得每个线程都可以独立地改变...
Java事务和ThreadLocal是两种在Java编程中至关重要的概念,它们分别用于处理多线程环境下的数据一致性问题和提供线程局部变量。 首先,我们来深入理解Java事务。在数据库操作中,事务是一系列操作的集合,这些操作...
### Java中ThreadLocal详解 #### 一、ThreadLocal概述 在Java多线程编程中,`ThreadLocal`是一个非常重要的工具类,它提供了一种在每个线程内部存储线程私有实例的方法。通常情况下,当多个线程共享某个变量时,...
ThreadLocal是Java编程中一种非常特殊的变量类型,它主要用于在多线程环境下为每个线程提供独立的变量副本,从而避免了线程间的数据共享和冲突。然而,ThreadLocal在理解和使用过程中容易产生一些误区,这里我们将...
**线程局部变量(ThreadLocal)** 在Java编程中,`ThreadLocal`是一个非常重要的工具类,它用于在多线程环境中提供线程安全的局部变量。`ThreadLocal`并不是一个线程,而是一个线程局部变量的容器,每个线程都有自己...