[多线程] - ThreadLocal的使用

一、TreadLocal是什么

在讲述概念前,我们还是先看下官方文档是怎么定义的:
在这里插入图片描述
观看官方文档,我们可以将Threadlocal做如下简单的定义:

  1. ThreadLocal是指的用来保存线程局部变量的一个类,既然用来保存数据,代表我们可以将ThreadLocal看做是一个容器。
  2. ThreadLocal是用来解决多个线程使用同一个共享变量的问题,其设计本质上讲应该是空间换取时间,简单来讲就是通过创建新的ThreadLocal容器来将共享变量的副本存放到每个线程中,以此来避免加锁带来的时间损耗,减少并发访问下的工作时间。

二、ThreadLocal的简单应用

这里我们先创建一个简单的Demo来看下ThreadLocal的应用:

public class ThreadLocalDemo_01 {
    
    
	private static String str;

	public static void main(String[] args) throws InterruptedException {
    
    
		str = "苹果";
		ThreadLocal<String> threadLocal = new ThreadLocal<String>();
		threadLocal.set(str);
		Stream.of("华为", "oppo", "锤子").forEach(s -> {
    
    
			Thread thread = new Thread(()->{
    
    
				String string = threadLocal.get();
				System.out.println(Thread.currentThread().getName()+" 线程拿到的变量值是:"+string);
				str =s ;
				threadLocal.set(str);
				string = threadLocal.get();
				System.out.println(Thread.currentThread().getName()+" 线程更新后的变量值是是:"+string);

			},s);
			thread.start();
		});
		Thread.sleep(1_000);
		String string = threadLocal.get();
		System.out.println(Thread.currentThread().getName()+" 线程拿到的变量值是:"+string);
		System.out.println("静态变量str的值为"+str);
	}
}

打印结果:
在这里插入图片描述

虽然我们往ThreadLocal里存放的都是相同的静态变量str,但是在str的值改变的时候,存放在ThreadLocal中的变量副本并没有发生改变,这就保证了我们引用的一直都是我们希望使用的变量值。

三、ThreadLocal的源码分析

这里我们在简单的分析下ThreadLocal的源码,来看下他是如何实现对线程局部变量的存储,这里我把有意义的源码站出来:

    // set方法
	public void set(T paramT) {
    
    
		Thread localThread = Thread.currentThread();
		ThreadLocalMap localThreadLocalMap = getMap(localThread);
		if (localThreadLocalMap != null) {
    
    
			localThreadLocalMap.set(this, paramT);
		} else {
    
    
			createMap(localThread, paramT);
		}
	}
	// 获取参数
	public T get() {
    
    
		Thread localThread = Thread.currentThread();
		ThreadLocalMap localThreadLocalMap = getMap(localThread);
		if (localThreadLocalMap != null) {
    
    
			ThreadLocal.ThreadLocalMap.Entry localEntry = localThreadLocalMap.getEntry(this);
			if (localEntry != null) {
    
    
				Object localObject = value;
				return (T) localObject;
			}
		}
		return (T) setInitialValue();
	}
	// 获取容器
	ThreadLocalMap getMap(Thread paramThread) {
    
    
		return threadLocals;
	}
	// 创建容器
	void createMap(Thread paramThread, T paramT) {
    
    
		threadLocals = new ThreadLocalMap(this, paramT);
	}
	//容器的本质
	ThreadLocalMap(ThreadLocal<?> paramThreadLocal, Object paramObject) {
    
    
			table = new Entry[16];
			int i = threadLocalHashCode & 0xF;
			table[i] = new Entry(paramThreadLocal, paramObject);
			size = 1;
			setThreshold(16);
		}

这里我们简单的分析下源码,其实通过ThreadLocal的源码可以证实我刚才的理论,ThreadLocal的本质就是一个容器,他是以当前的线程为key,传入的object对象为value进行存储,这样当不同的参数调用get方法的时候,他会以线程作为key去查找value,已达到避免多个线程对同一个变量进行修改的目的。

四、InheritableThreadLocal

作为ThreadLocal的子类,它其实主要是为了实现父子线程之间的变量共享问题,这个由于平时应用并不是很多,所以我这边就不做赘述,感兴趣的同学可以看下这篇博客:

https://zhuanlan.zhihu.com/p/101780720

写这篇文章时刚好感到成都爆发新冠疫情,公司人心惶惶,这篇可能写的有些粗略,如果之后有机会我会将这篇重新的写一下,多增加一些举例,好了就吐槽到这吧!

猜你喜欢

转载自blog.csdn.net/xiaoai1994/article/details/110873863
今日推荐