前言
- ThreadLocal给每个线程创建一个副本,方便线程存储本地数据。ThreadLocal不存在线程之间的数据传递,只会保证在同一个线程的生命周期内随时访问,存储数据。本文会介绍一下Threadlocal的使用场景,Thread和ThreadLocal之间的关系。
使用场景
- 私有化的数据存储可以直接使用对象,但是这样需要在不同的类和方法之间传递数据存储对象。也可以使用静态化存储,但是静态存储是线程共享的,如果存储数据在线程生命周期内会有变化,那么我们还需要维护容器的线程安全,这是一笔很大的开销,没有必要的情况下,尽量不要使用。而ThreadLocal是介于二者之间的优化实践。
public class AccessContext {
private static final ThreadLocal<String> REQUEST_IP = new ThreadLocal<>();
public static void setRequestIp(String ip) {
REQUEST_IP.set(ip);
}
public static String getRequestIp() {
return REQUEST_IP.get();
}
public static void clearAll() {
REQUEST_IP.remove();
}
}
- 什么情况下使用ThreadLocal?线程间共享范围太大,对象存储范围太小的时候。
- 都说java是面向对象的编程。说下我对对象编程的理解:蚁族中有工蚁,兵蚁,蚁后等,那么对象在我看来颇有相似之处。对象有数据存储对象,功能对象,结构对象,生产对象的对象,熟悉设计模式的可能理解更加深刻一些。面向对象编程就是:创建对象,组合对象。不同属性对象组成不同功能框架,不同功能框架组成不同应用。
原理
-
什么时候需要我们使用ThreadLocal?每个独立的java应用都是一个进程,进程中是线程的生生灭灭,而我们的代码真正生活的地方叫线程。来张图看下进程,Thread,ThreadLocal在计算机中的位置关系,很简单~
线程本地存储
-
很显然,Thread中有一个对象的引用,指向ThreadLocalMap,这个Map容器的定义和操作处理在ThreadLocal中定义,稍后介绍ThreadLocalMap,想一下它和普通的HashMap有什么区别?为什么不直接使用HashMap存储呢?
image.png
-
Thread中使用threadLocalMap的情况,很显然,都在ThreadLocal中。看下它的使用情况:
image.png
-
在Thread中,exit()方法是系统调用,在线程真正结束之前会释放资源,反之,线程没有结束的时候ThreadLocalMap不会释放,有些时候需要手动释放。
image.png
-
上面这个方法来自ThreadLocal,从一个Thread中取出它的存储对象ThreadLocalMap。
ThreadLocalMap
-
对象的存储结构是个永恒的话题。ThreadLocalMap是自定义的Map,不是Map的子类。这个Map是Entry组成的,看它继承了WeakReference,弱引用。
image.png
-
把对象存入Thread,使用Threadlocal.
1.获得当前线程Thread对象;
2.getMap(t)获得数据存储对象ThreadLocalMap;
3.如果map是空的,初始化threadLocals,否则把数据存入map。
image.png

-
获得ThreadLocal中存储的对象
1.首先获得线程对象
2.获得数据存储对象
3.如果Map不是null,获得Entry,entry中取到存储的数据
4.map是null的,需要初始化
image.png
image.png
网友评论