关于ThreadLocal的简单理解与源码山寨

本文深入解析了ThreadLocal的作用原理及其实现方式,通过对比同步块,突出了ThreadLocal在线程安全问题上的优势,并介绍了其在数据库连接等场景的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.为什么使用ThreadLocal?

                当我们进行java的相关操作的时候,有时候并不是想 这个资源进行共享 只是有的时候,一些代码导致这个资源得到共享了,那么就可以通过ThreadLocal来进行密封操作这个资源,然后为每一次访问此资源的线程都创建一个副本,有人会问那么为什么不适用同步块呢,因为,同步块解决线程安全问题的时候,其他线程都会排队等待,这就导致了时间上耗费过多的问题,但是他每次知识访问的同一个资源,节省了内存。通过同步块来解决线程安全问题,会比ThreadLocal慢150倍左右, 用ThreadLocal来解决的时候,是为每个变量创建一个副本,节约了排队等待的时间,但是耗费了内存 

         还可以通过其他的方式来避免,比如说当属性私有化的时候只提供set方法,没有get方法 就是只读,那么就不会有线程安全问题了,还有就是不提供成员变量,再有就是无状态对象,就是在对象之中的方法没有 设置值。

2.ThreadLocal的山寨,与应用场景

    其实ThreadLocal有用的方法只有三个,set(对象),get(),remove(),并且一个ThreadLocal里面只能有一个对象

比如:

    

public class TestThreadLocal {
	private static ThreadLocal<Integer> tl = new ThreadLocal<Integer>(){
		@Override
		protected Integer initialValue() {
			// TODO Auto-generated method stub
			return 0;//初始化方法,当调用get方法为空的时候,这个方法会自动为ThreadLocal设置值
		}
	};
	public static Integer bb(){
		
		tl.set(tl.get()+1);
		return tl.get();
	}
	@Test
	public void test(){
		
		
  		new Thread(){
			public void run(){
				for (int i = 0; i < 10; i++) {
					System.out.println(Thread.currentThread().getName()+" "+TestThreadLocal.bb());
				}
				
			}
		}.start();
		new Thread(){
			public void run(){
				for (int i = 0; i < 10; i++) {
					System.out.println(Thread.currentThread().getName()+" "+TestThreadLocal.bb());
				}
			}
		}.start();
	}
}

运行结果如下

Thread-0 1
Thread-0 2
Thread-0 3
Thread-0 4
Thread-0 5
Thread-0 6
Thread-0 7
Thread-0 8
Thread-0 9
Thread-0 10
Thread-1 1
Thread-1 2
Thread-1 3
Thread-1 4
Thread-1 5
Thread-1 6
Thread-1 7
Thread-1 8
Thread-1 9
Thread-1 10



大家可以看到,两个线程之间并没有对Integer产生影响,而是每一个线程都得到了自己的副本。说了这么多,可能还是有一些迷糊,现在我山寨一下ThreadLocal的
实现,因为源码比较难懂,这里简单的山寨,相信,看了这里,你在看一些大神的博客分析这里的源码会理解很多,其实ThreadLocal本质来说是一个map类型的,
内部的数据结构就是map ,山寨完我用一张图解释一下上面的过程,就容易理解了

山寨开始

class ThreadLocal<T>{
 	private Map<Thread,T> map = new HashMap<Thread,T>();
 	public void set(T data){
 		map.put(Thread.currentThread(),data);
 	}
 	public T get(){
 		return map.get(Thread.currentThread());
 	}
 	public void remove(){
 		map.remove(Thread.currentThread());
 	}
 }

ThreadLocal时以当前线程做key,以要保护的变量做值,当一个线程向要得到值的时候,如果不是当前线程,那么就得不到这个变量,因为他不是这个value的值,只能是自己在创建一个副本。保存自己作为key,这样这个value就归自己所有了。与其他线程互相不干扰

好了现在用一张图,来解释上面的代码

这里只是解释了其中一个循环所做的事,但是见微知著,相信大家都已经理解了。

3.那么ThreadLocal都应用在什么上面呢?

    主要是数据库和一些其他非共享变量上面。

    因为数据库连接不能是一个线程正在open,一个close吧(正常情况),还有就是用户操作数据库,不能排队等待吧(同步块),这样用户体验度会很差的。当然了,除了用这种方式,还可以用线程池来解决,好了吗,这就是全部内容,不知道大家懂了吗。如果我说的哪里有毛病,欢迎来批评指正。




            

    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值