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 ThreadLocal类深入】 Java中的ThreadLocal类是一种线程绑定机制,用于在多线程环境中为每个线程提供独立的变量副本,避免了线程间的数据共享带来的并发访问问题。ThreadLocal并不是一个线程对象,而是线程...
Java中的`ThreadLocal`类是一个非常实用的工具,它提供了线程局部变量的功能。线程局部变量意味着每个线程都拥有自己独立的变量副本,互不干扰,这在多线程编程中尤其有用,可以避免数据共享带来的同步问题。下面...
Java线程编程中的ThreadLocal类是一个非常重要的工具,它在多线程环境下提供了一种线程局部变量的机制。ThreadLocal并非是简单的变量,而是一种能够确保每个线程都拥有独立副本的变量容器。理解ThreadLocal的工作...
**线程局部变量(ThreadLocal)是Java编程中一个非常重要的工具类,它在多线程环境下提供了线程安全的数据存储。ThreadLocal并不是一个变量,而是一个类,它为每个线程都创建了一个独立的变量副本,使得每个线程都...
Java中的ThreadLocal类是一个强大的工具,它允许程序员创建线程局部变量。这意味着每个线程都有其自己独立的、不可见的变量副本,从而避免了线程间的数据共享问题,简化了多线程环境下的编程复杂性。ThreadLocal并不...
Java ThreadLocal类应用实战案例分析 Java ThreadLocal类是Java语言中的一种线程局部变量机制,允许每个线程都拥有自己的变量副本,从而避免了多线程之间的变量冲突。在本文中,我们将通过实战案例分析Java ...
Java中ThreadLocal工具类(解决多线程程序中并发问题的一种新思路,主要为参数的拷贝问题),感兴趣的话可以查看博文,博文地址:http://blog.csdn.net/otengyue/article/details/38459327
### 知识点详解:Java.lang.ThreadLocal 类 #### 一、概述 **ThreadLocal** 并非线程的一种特殊实现形式,而是一种为每个线程提供独立副本的机制,通常被称为“线程局部变量”。这种机制使得每个线程都可以独立...
ThreadLocal是Java编程语言中的一个类,用于在多线程环境中提供线程局部变量。它是一种特殊类型的变量,每个线程都有自己的副本,互不影响,从而实现线程间数据隔离。ThreadLocal通常被用来解决线程共享数据时可能...
DbUTils中用ThreadLocal类
`ThreadLocal` 是 Java 中用于在单个线程内存储线程局部变量的类,每个线程都有自己的副本,不会互相干扰。`MyThreadLocal` 是 `ThreadLocal` 的子类,用于存储 `MyCounter` 对象。在 `LeakingServlet` 的 `doGet` ...
在这个例子中,`ConnectionHolder`类提供了一组静态方法来设置、获取和移除线程局部的`Connection`对象。当多个线程并发执行时,每个线程都可以安全地使用自己的`Connection`实例,而不会相互干扰。 总的来说,结合...
这个功能是通过 Thread 类中的 threadLocals 属性来实现的,这个属性实际上是一个 Entry 数组,其中的每个 Entry 都是一个弱引用,易于在 GC 时被回收。 ThreadLocal 的工作机制是通过计算Hash值来确定在数组中的...
2. **内部类ThreadLocalMap**: `ThreadLocalMap`是`ThreadLocal`类中的一个内部静态类,它是一个定制的哈希映射,专门用于存储线程局部变量。每个`Thread`对象都包含一个`ThreadLocalMap`实例,用于保存该线程的`...
本资料主要聚焦于两种设计模式以及Java中的ThreadLocal特性。 首先,我们来探讨单例模式。单例模式是一种确保一个类只有一个实例,并提供全局访问点的设计模式。在Java中,通常通过私有构造函数、静态工厂方法或...
Java中的ThreadLocal是一个非常重要的工具类,它在多线程编程中扮演着独特角色,尤其在处理线程间数据隔离和共享时。ThreadLocal不是线程本身,而是为每个线程提供一个独立的变量副本,使得每个线程都可以独立地改变...