java中ThreadLocal对象理解和使用
对ThreadLocal的理解
**个人理解:**用一个ThreadLocal可以用来为每个线程独立存储一个对象,让每个线程都有唯一的副本。每一个线程读取的变量是对应的互相独立的。通过get和set方法就可以得到当前线程对应的值。
如果单单从使用的角度可以理解为(实际不是这样):
ThreadLocal相当于维护了一个map,key就是当前的线程,value就是需要存储的对象。
实际存储结构是:
线程Thread中维护了一个ThreadLocalMap对象,ThreadLocalMap对象是以ThreadLocal作为key,存储数据。一个Thread中可能会定义多个ThreadLocal对象。
使用ThreadLocal
代码如下:
package com.study.threadLocal使用;
import java.util.Random;
import org.apache.commons.lang3.StringUtils;
public class TestThreadLocal2 implements Runnable
{
private static final ThreadLocal<TestObject> formatter = ThreadLocal.withInitial(() -> new TestObject());
/*
* ||
*/
private static final ThreadLocal<TestObject> formatter2 = new ThreadLocal<TestObject>(){
@Override
protected TestObject initialValue()
{
TestObject obj = new TestObject();
return obj;
}
};
public static void main(String[] args) throws InterruptedException {
TestThreadLocal2 obj = new TestThreadLocal2();
for(int i=0 ; i<3; i++){
Thread t = new Thread(obj, ""+i);
Thread.sleep(new Random().nextInt(1000));
t.start();
}
}
@Override
public void run() {
String name = Thread.currentThread().getName();
if(StringUtils.equals(name, "0")){
TestObject obj = formatter.get();
obj.setName("小白");
formatter.set(obj);
}
if(StringUtils.equals(name, "1")){
TestObject obj = formatter.get();
obj.setName("小红");
formatter.set(obj);
}
System.out.println("ThreadLocal对象:"+formatter);
System.out.println("Thread Name= "+name+" formatter = "+formatter.get());
System.out.println();
}
static class TestObject {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
运行结果如下:
同运行结果可以看出:3个线程打印的ThreadLocal对象是同一个。而ThreadLocal中村拆除的TestObject对象,每个线程都是不同的对象。
简单了解ThreadLocal源码
通过set方法简单看下源码:
先通过当前线程获取ThreadLocalMap对象。如果没有,则创建ThreadLocalMap,将value存入。
观察创建ThreadLocalMap对象,createMap方法会创建一个ThreadLocalMap对象,并把该对象赋值给当前线程的成员变量threadLocals。可以想得到,这个地方每个线程调用set时,t都是不同的。
ThreadLocalMap的构造方法:会将ThreadLocal经过hash得到一个下标作为key,将value存储到ThreadLocalMap中的table中。这个地方需要注意的是,ThreadLocal<?> firstKey
针对于所有线程,都是同一个对象。但是看上一步赋值的时候,每个线程调用的t都是不同的。
每个线程持有一个ThreadLocalMap对象。每一个新的线程Thread都会实例化一个ThreadLocalMap并赋值给成员变量threadLocals,使用时若已经存在threadLocals则直接使用已经存在的对象。
借用ingxin大佬的总结:
1、对于某一ThreadLocal来讲,他的索引值i是确定的,在不同线程之间访问时访问的是不同的table数组的同一位置即都为table[i],只不过这个不同线程之间的table是独立的。
2、对于同一线程的不同ThreadLocal来讲,这些ThreadLocal实例共享一个table数组,然后每个ThreadLocal实例在table中的索引i是不同的。
上一篇: 教务管理系统之单门成绩录入模块
推荐阅读
-
java对象是什么意思(java中的对象和类理解)
-
Java中HashMap和TreeMap的区别深入理解
-
Python中@property的理解和使用示例
-
详解java中的深拷贝和浅拷贝(clone()方法的重写、使用序列化实现真正的深拷贝)
-
Java中对象数组的使用方法详解
-
微信小程序授权 获取用户的openid和session_key【后端使用java语言编写】,我写的是get方式,目的是测试能否获取到微信服务器中的数据,后期我会写上post请求方式。
-
Kotlin中的对象表达式和对象声明的具体使用
-
PHP使用正则表达式获取微博中的话题和对象名
-
java中List对象的操作方法和List对象的遍历
-
Java的类与对象定义和使用