上个星期听大佬说了线程变量,所以做了下ThreadLocal的笔记

java.lang.ThreadLocal
一、什么是ThreadLocal?
        
        ThreadLocal为线程变量,意思是ThreadLoacl中填充的变量属于当前线程所有,该变量对于其他线程而言是隔离的
     
          使用场景:
 
            1. 在进行对象跨层传递时,使用ThreadLocal可以避免多次传递,打破层次间的约束;
            2. 线程间数据隔离;
            3. 进行事务操作,用于存储线程事务信息;
            4. 数据库连接,Session会话管理。
 
二、ThreadLocal怎么用?
 
package com.xs.thread.threadlocal ;
 
import java.util.Random ;
import java.util.concurrent. TimeUnit ;
import java.util.stream. IntStream ;
 
/**
* @author: xusheng
* @create-time 2020-08-19 21:31
**/
public class ThreadLocalTest {
 
public static void main ( String [] args ) {
 
 
 
Random random = new Random () ;
 
IntStream .range ( 0 , 5 ) . forEach ( a -> new Thread (() -> {
ThreadLocal < String > local = new ThreadLocal <> () ;
local . set ( a + " " + random . nextInt ( 10 )) ;
System . out . println ( " 线程和 local 值分别为 " + local . get ()) ;
try {
TimeUnit . SECONDS . sleep ( 5 ) ;
} catch ( InterruptedException e ) {
e . printStackTrace () ;
}
}) . start ()) ;
}
}
一般都在数据库连接时使用的比较多
 
三、ThreadLocal源码分析 (ThreadLocalMap中的key为ThreadLocal的实例变量)
 
1、set方法
 
public void set ( T value ) {
Thread t = Thread .currentThread () ;
ThreadLocalMap map = getMap ( t ) ;
if ( map != null )
map . set ( this , value ) ;
else
createMap ( t , value ) ;
}
首先获取到了当前线程t,然后调用getMap获取ThreadLocalMap,如果map存在,则将当前线程对象t作为key,要存储的对象作为value存到map里面去。如果该Map不存在,则初始化一个。
 
ThreadLocalMap
 
static class ThreadLocalMap {
 
/**
* The entries in this hash map extend WeakReference, using
* its main ref field as the key (which is always a
* ThreadLocal object). Note that null keys (i.e. entry.get()
* == null) mean that the key is no longer referenced, so the
* entry can be expunged from table. Such entries are referred to
* as "stale entries" in the code that follows.
*/
static class Entry extends WeakReference < ThreadLocal <?>> {
/** The value associated with this ThreadLocal. */
Object value ;
 
Entry ( ThreadLocal <?> k , Object v ) {
super ( k ) ;
value = v ;
}
}
我们可以看到ThreadLocalMap其实就是ThreadLocal的一个静态内部类,里面定义了一个Entry来保存数据,而且还是继承的弱引用。准确来说,是key为弱引用
 
2、get方法
 
public T get () {
Thread t = Thread .currentThread () ;
ThreadLocalMap map = getMap ( t ) ;
if ( map != null ) {
ThreadLocalMap . Entry e = map . getEntry ( this ) ;
if ( e != null ) {
@SuppressWarnings ( "unchecked" )
T result = ( T ) e . value ;
return result ;
}
}
return setInitialValue () ;
}
首先获取当前线程,然后调用getMap方法获取一个ThreadLocalMap,如果map不为null,那就使用当前线程作为ThreadLocalMap的Entry的键,然后值就作为相应的的值,如果没有那就设置一个初始值。
 
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 ;
}
3、总结
(1)每个Thread维护着一个ThreadLocalMap的引用
(2)ThreadLocalMap是ThreadLocal的内部类,用Entry来进行存储
(3)ThreadLocal创建的副本是存储在自己的threadLocals中的,也就是自己的ThreadLocalMap。
(4)ThreadLocalMap的键值为ThreadLocal对象,而且可以有多个threadLocal变量,因此保存在map中
(5)在进行get之前,必须先set,否则会报空指针异常,当然也可以初始化一个,但是必须重写initialValue()方法。
(6)ThreadLocal本身并不存储值,它只是作为一个key来让线程从ThreadLocalMap获取value。
 
 
 
 
 
 
 
 
 
 
 
 
        
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值