ThreadLocal,本地线程变量,每个线程保留着一个共享变量的副本。其实我不太认可每个线程保存共享变量的一个副本这个说法,而是ThreadLocal是线程上下文环境的一种实现方式而已。就以数据库事务这一常用场景来举例说明,比如每个线程需要访问数据库,就需要获取数据库的连接Connection对象,在实际中,我们会用数据库连接池来重复利用Connection,首先线程池,这里是一个共享变量,线程池的实现必须保证多个线程同时从线程池中获取Connection不会重复,然后每个线程使用单独的Connection,并且该Connection被一个线程占用后,其他线程压根就不会使用到,也不会试图去使用一个已经被其他线程占用的Connection对象。由于一个线程在执行过程中,可能需要多次操作数据库,所以我们的设计就是一个线程在执行过程中,只与一个Connection打交道,也就是整个线程的执行过程(执行环境)需要保存刚获取的Connection,最简单有效的办法,就是把这个Connection保存在线程对象的某个属性中,ThreadLocal就是干这事的。ThreadLocal并不是为这个Connection复制一份,多个线程都使用这个副本,不是这样的,一个Connection对象在任意时刻,没有被复制多份。
我的观点:ThreadLocal是线程一个本地变量,是线程的执行上下文。
2、 从ThreadLocal get方法源码分析其实现逻辑
==============================
/**
-
Returns the value in the current thread’s copy of this
-
thread-local variable. If the variable has no value for the
-
current thread, it is first initialized to the value returned
-
by an invocation of the {@link #initialValue} method.
-
@return the current thread’s value of this thread-local
*/
public T get() {
Thread t = Thread.currentThread(); //@1
ThreadLocalMap map = getMap(t); //@2
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this); //@3
if (e != null)
return (T)e.value;
}
return setInitialValue(); // @4
}
代码@1:获取当前线程。
代码@2:从当前线程获取ThreadLocalMap。
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
这里是直接返回线程对象的threadLocals变量,有点意思吧,所以说ThreadLocal,是线程的本地变量,就是这层意思,真正存放数据的地方,就是线程对象本身,其实接下来的会更加有意思:我们进入ThreadLocalMap源码分析,得知,原来ThreadLocalMap就是一个Map结构(K-V)键值对,关于里面的源码就不一一分析了,ThreadLocalMap(ThreadLocal firstKey, Object firstValue),firstKey 为ThreadLocal,神奇吧,其实这也是为什么Thread的本地变量的数据类型为Map的原型,一个线程可以被多个ThreadLocal关联,每声明一个,就在线程的threadLocals增加为一个键值对,key 为 ThreadLocal,而value为具体存放的对象。
代码@3:如果线程的ThreadLocalMap不为空,则直接返回对,否则进入到代码@4
代码@4:初始化并获取放入ThreadLocal中的变量。
上面就是ThreadLocal的核心设计理念,为了更加直观的说明ThreadLocal原理,举例说明:
public class ThreadLocalDemo1 {
private static final ThreadLocal schemaLocal
= new ThreadLocal();
public void test1() {
String a = schemaLocal.get();
ThreadLocalDemo2 demo2 = new ThreadLocalDemo2();
demo2.test(a);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
}
}
public class ThreadLocalDemo2 {
private static final ThreadLocal slocal = new ThreadLocal();
public void test(String b) {
String a = slocal.get();
// 其他代码
System.out.println(b);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
}
}
public class TestMain {
public static void main(String[] args) {
// TODO Auto-generated method stub
ThreadLocalDemo1 d = new ThreadLocalDemo1();
d.test1();
}
}
一个线程调用 ThreadLocalDemo1 的 test1方法,在这个执行链中会涉及到两个ThreadLocal变量,调用ThreadLocal的get方法,首先会获取当前线程,然后从当前线程对象中获取线程内部属性[ThreadLocal.ThreadLocalMap threadLocals = null;],然后从ThreadLocalMap中以ThreadLocal对象为键,从threadLocals map中获取存放的值。
线程的threadLocals值为
{
ThreadLocalDemo1.schemaLocal : 该变量中的值,
ThreadLocalDemo2.scloal : 存放在本线程中的值
}
3、 ThreadLocal优化思考
==================
ThreadLocal的数据访问算法,本质上就是Map的访问特性。
我在分析HashMap源码的时候,已经将HashMap的存储结构讲解完毕,如有兴趣,可以浏览一下我的博文:深入理解HashMap:http://blog.csdn.net/prestigeding/article/details/52861420,HashMap根据key的访问速度效率是很快的,为什么呢?因为HashMap根据key的hash,然后会定位到内部的数据槽(该数据是数组结构),众所周知,根据数组的下标访问,访问速度是最快的,也就是说HashMap根据key的定位速度比LinkedList等都快,仅次于数组访问方式,这是因为HashMap多了一步Hash定位槽的过程(当然,如果有Hash冲突那就更慢了)。所以,如果在高并发场景下,需要进一步优化ThreadLocal的访问性能,那就要从线程对象(Thread的threadLocals 数据结构下手了,如果能将数据结构修改为数组,然后每个ThreadLocal对象维护其下标那就完美了)。是的,Netty框架就是为了高并发而生的,由于并发访问的数量很大,一点点的性能优化,就会带来可观的性能提升效应,Netty主要从如下两个方面对ThreadLocal的实现进行优化
-
线程对象直接提供 set、get方法,以便直接获取线程本地存储相关的变量属性。
-
将数据存储基于数组存储。
4、Netty关于ThreadLocal机制的优化
=========================
由于ThreadLocal是JDK的原生实现,通用性很强,直接扩展进行定制化不是明智的选择,故Netty在优化ThreadLocal的方式是自己另起灶炉,实现ThreadLocal的语义。优化方法如下:
-
提供一个接口,FastThreadLocalAccess,并对线程池工厂类进行定制,创建的线程继承在java.lang.Thread类,并实现FastThreadLocalAccess接口,提供直接设置,获取线程本地变量的方法。
-
提供FastThreadLocal类,此类实现ThreadLocal相同的语义。
-
提供InternalThreadLocalMap类,此类作用类同于java.lang.ThreadLocal.ThreadLocalMap类,用于线程存放真实数据的结构。
4.1 扩展线程对象,提供set,get方法
最后
即使是面试跳槽,那也是一个学习的过程。只有全面的复习,才能让我们更好的充实自己,武装自己,为自己的面试之路不再坎坷!今天就给大家分享一个Github上全面的Java面试题大全,就是这份面试大全助我拿下大厂Offer,月薪提至30K!
我也是第一时间分享出来给大家,希望可以帮助大家都能去往自己心仪的大厂!为金三银四做准备!
一共有20个知识点专题,分别是:
Dubbo面试专题
JVM面试专题
Java并发面试专题
Kafka面试专题
MongDB面试专题
MyBatis面试专题
MySQL面试专题
Netty面试专题
RabbitMQ面试专题
Redis面试专题
Spring Cloud面试专题
SpringBoot面试专题
zookeeper面试专题
常见面试算法题汇总专题
计算机网络基础专题
设计模式专题
dJ4gWEO-1714430764605)]
SpringBoot面试专题
[外链图片转存中…(img-miG9ovLE-1714430764605)]
zookeeper面试专题
[外链图片转存中…(img-wGvBF5xR-1714430764606)]
常见面试算法题汇总专题
[外链图片转存中…(img-gVPRSJ4z-1714430764606)]
计算机网络基础专题
[外链图片转存中…(img-OQ2unhqg-1714430764607)]
设计模式专题
[外链图片转存中…(img-iHRLmXEs-1714430764607)]