ThreadLocal类在Spring等框架中扮演了一个很重要的角色,本文就从源码的角度揭开它羞涩的面纱。
废话不少,先看看可以怎么使用:
Person类:
public class Person {
private String name;
private int age;
public Person(String name, int age)
{
this.name = name;
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
TLPerson类:我理解为Person的线程变量包装类
public class TLPerson {
//一般采用私有静态的方式定义
private static ThreadLocal<Person> persontl = new ThreadLocal<Person>()
{
protected Person initialValue() {
return new Person("zubin" + Thread.currentThread().getId(), 31);
}
};
public Person getPerson()
{
Person p = persontl.get();
if(p == null)
{
persontl.set(new Person("zubin" + Thread.currentThread().getName(),13));
p = persontl.get();
}
return p;
}
public void setPerson(Person p)
{
persontl.set(p);
}
}
线程测试类:大家注意run方法中没有同步块
public class ThreadRunnable implements Runnable {
TLPerson tlp;
TLPerson tlp2;
public ThreadRunnable(TLPerson tlp, TLPerson tlp2)
{
this.tlp = tlp;
this.tlp2 = tlp2;
}
public void run() {
System.out.println(tlp.getPerson().getName() + " : " +tlp.getPerson().getAge());
tlp2.setPerson(new Person("abc" + Thread.currentThread().getId() ,33));
System.out.println(tlp2.getPerson().getName() + " : " +tlp2.getPerson().getAge());
}
public static void main(String ... args)
{
TLPerson tlp = new TLPerson();
TLPerson tlp2 = new TLPerson();
ThreadRunnable tr1 = new ThreadRunnable(tlp, tlp2);
ThreadRunnable tr2 = new ThreadRunnable(tlp, tlp2);
new Thread(tr1).start();
new Thread(tr2).start();
}
}
运行下测试线程,结果如下:
zubin7 : 31
abc7 : 33
zubin8 : 31
abc8 : 33
从结果可以看出,虽然两个线程都使用了相同的“TLPerson”,但是互相之间并无影响。
为什么呢,先来看ThreadLocal和Thread的关系
从上图可以看出,ThreadLocal和Thread是通过ThreadLocalMap这个内部类关联在一起的。
look:
public class Thread implements Runnable {
。。。
/*
* InheritableThreadLocal values pertaining to this thread. This map is
* maintained by the InheritableThreadLocal class.
*/
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
。。。
}
step1:
当我们在创建Thread对象
ThreadRunnable tr1 = new ThreadRunnable(tlp, tlp2);
new Thread(tr1).start();
这时tr1的inheritableThreadLocals为空。
step2:
tr1开始执行run方法,执行
System.out.println(tlp.getPerson().getName() + " : " +tlp.getPerson().getAge());
我们看下tlp.getPerson()是怎么做的?
step3:
public Person getPerson()
{
Person p = persontl.get();
if(p == null)
{
persontl.set(new Person("zubin" + Thread.currentThread().getName(),13));
p = persontl.get();
}
return p;
}
从 persontl.get()方法进去了,我们看一下ThreadLocal的实现:
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
return (T)e.value;
}
return setInitialValue();
}
获取当前线程t的map,这个时候肯定是为null,所以会执行 setInitialValue()方法
private T setInitialValue() {
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}
首先通过 initialValue()方法获取初始值,这个方法我们在匿名内部类做了重写
private static ThreadLocal<Person> persontl = new ThreadLocal<Person>()
{
protected Person initialValue() {
return new Person("zubin" + Thread.currentThread().getId(), 31);
}
};
然后去获取map,ThreadLocalMap map = getMap(t);这个时候map还是为空,进入createMap()方法
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
在这个方法里才给Thread创建了map,并且把new Person("zubin" + Thread.currentThread().getId(), 31);对象存入map中。
注意了,是new的一个对象哟,这是理解ThreadLocal的关键
ThreadRunnable tr2 = new ThreadRunnable(tlp, tlp2);
new Thread(tr2).start();
tr2重复了step1、2、3.
O(∩_∩)O哈哈~,到次我们发现每个线程都有一个map,里面存放的以ThreadLocal对象为key,new的“共享”变量为value。也就是说每个线程的对象都是自己私人的,当然也就不会存在同步的问题了。
好处就是以空间换时间了,没有锁竞争了。
分享到:
相关推荐
深入研究java.lang.ThreadLocal类。ThreadLocal是什么呢?其实ThreadLocal并非是一个线程的本地实现版本,它并不是一个Thread,而是 threadlocalvariable(线程局部变量)。也许把它命名为ThreadLocalVar更加合适。
入研究java.lang.ThreadLocal类.docx
Java中ThreadLocal工具类(解决多线程程序中并发问题的一种新思路,主要为参数的拷贝问题),感兴趣的话可以查看博文,博文地址:http://blog.csdn.net/otengyue/article/details/38459327
NULL 博文链接:https://justsee.iteye.com/blog/791919
简单分析Java线程编程中ThreadLocal类的使用共4页.pdf.zip
DbUTils中用ThreadLocal类
主要介绍了Java ThreadLocal类应用,结合具体案例形式分析了java ThreadLocal类的功能、原理、用法及相关操作注意事项,需要的朋友可以参考下
ThreadLocalMap是ThreadLocal类中的内部类,实例却被Thread类持有,相当于每个线程持有一个map
ThreadLocal入门教程。 讲解了线程安全和ThreadLocal的使用的基本知识。
什么是ThreadLocal?顾名思义它是local variable(线程局部变量)。它的功用非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突...
ThreadLocal
ThreadLocal应用示例及理解,这个写了相关的示例,可以参考一下。
JDBC事务的封装和Threadlocal实例,参考博客:http://blog.csdn.net/daijin888888/article/details/50988053
理解ThreadLocal 理解ThreadLocal 理解ThreadLocal 理解ThreadLocal
学习ThreadLocal,了解其中的原理,以及学习其中的优点!避免坑点!!
正确理解ThreadLocal.pdf
ThreadLocal保证一个类的实例变量在各个线程中都有一份单独的拷贝, 从而不会影响其他线程中的实例变量
主要介绍ThreadLocal的原理,实例分析以及注意事项