深入理解ThreadLocal
来源:互联网 发布:android 监听网络断开 编辑:程序博客网 时间:2024/05/30 23:55
当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
应用实例:
1.
package com.liuhui.thread;public class ThreadLocalDemo {private static ThreadLocal<Integer>t=new ThreadLocal<Integer>();public static int test(){ Integer num=t.get();if(num==null){ num=10; t.set(num); } return num;}public static void main(String[] args) { System.out.println(test());}}
2.
package com.liuhui.thread;import java.sql.Connection;import java.sql.DriverManager;import java.sql.SQLException;public class TestConn {private static ThreadLocal<Connection>t=new ThreadLocal<Connection>();public static Connection test() throws SQLException { Connection conn=t.get(); if(conn==null){conn=DriverManager.getConnection("","","");t.set(conn); } return conn;}public static void main(String[] args) throws Exception { System.out.println(test());}}
3.
输出结果:可以看到各个线程之间的变量是独门的,不会相影响。
通过上面的一个实例,简单的了解了ThreadLocal的用法,下面再来看下其源码实现。
ThreadLocal是如何做到为每一个线程维护变量的副本的呢?其实实现的思路很简单:在ThreadLocal类中有一个Map,用于存储每一个线程的变量副本,Map中元素的键为线程对象,而值对应线程的变量副本。
下面分析其源码
首先是其包含的方法:
它的构造函数不做什么:
其实主要的也就下面几个方法:
(1)get这个上方法就是用来取得变量的副本的,注意到它先取得了当前线程对象,接下来使用了getMap返回一个ThreadLocalMap
然后可以知道ThreadLocalMap这个竟然是从线程中取到的,好,再打开线程类看看
发现Thread类中有这样一个变量:
也变是说每一个线程都有自己一个ThreadLocalMap。在我们第一次调用get()函数 时,getMap函数返回的是一个null的map.接着就调用setInitialValue()
看看setInitialValue,它才是真正去初始化map的地方!
其中initialValue这个方法就是我们要重写的,一般我们在这里通过一个new 方法返回一个新的变量实例
因为是第一次调用get(),所以getMap后的map还是为null。这时就调用到createMap
终于创建ThreadLocalMap!这里就将Thread和我们的ThreadLocal通过一个map关联起来。意思是每个Thread中都有一个ThreadLocal.ThreadLocalMap。其中Key为ThreadLocal这个实例,value为每次initialValue()得到的变量!
接下来如果我们第二次调用get()函数,这里就会进入if方法中去!
进入If方法中后。就会根据当前的thradLocal实例为Key,取得thread中对应map的vale.其中getEntry方法只是取得我们的key-value对。注意,这时的table其实就是在ThreadLocal实例中都会记录着每个和它关联的Thread类中的ThreadLocalMap变量是取得我们的key-value对之后就可取value了,然后就是返回result.如果这时取不到entry,那么又会调用到setInitalValue()方法,过程又和上面的一样了。这里就不说了!(2)set
这个方法就是重新设置每一个线程的本地ThreadLocal变量的值
这里取得当前线程,然后根据当前的thradLocal实例取得其map。然后重新设置 map.set(this, value);这时这个线程的thradLocal里的变量副本就被重新设置值了!(3)remove
就是清空ThreadLocalMap里的value,这样一来。下次再调用get时又会调用 到initialValue这个方法返回设置的初始值
总结:
1、每个线程都有自己的局部变量
每个线程都有一个独立于其他线程的上下文来保存这个变量,一个线程的本地变量对其他线程是不可见的(有前提,后面解释)
2、独立于变量的初始化副本
ThreadLocal可以给一个初始值,而每个线程都会获得这个初始化值的一个副本,这样才能保证不同的线程都有一份拷贝。
3、状态与某一个线程相关联
ThreadLocal 不是用于解决共享变量的问题的,不是为了协调线程同步而存在,而是为了方便每个线程处理自己的状态而引入的一个机制,理解这点对正确使用ThreadLocal至关重要。
- 深入理解ThreadLocal
- ThreadLocal深入理解
- ThreadLocal深入理解2
- ThreadLocal深入理解
- 深入理解ThreadLocal
- 深入理解ThreadLocal
- ThreadLocal深入理解
- 深入理解ThreadLocal
- 深入理解ThreadLocal
- 深入理解ThreadLocal
- 深入理解ThreadLocal
- ThreadLocal深入理解 修订版
- 深入理解ThreadLocal
- 深入理解ThreadLocal
- 【Java】深入理解ThreadLocal
- 深入理解ThreadLocal
- 深入理解ThreadLocal
- 深入理解ThreadLocal
- mysql复合语句、存储过程、游标
- lightoj1058 && poj1791 求平行四边形个数
- URAL 2018 The Debut Album DP中滚动数组用法
- 阿里陶宝技术架构产品(OceanBase&CoBar)
- 控制器中view的创建方式小结
- 深入理解ThreadLocal
- 父Activity(A)启动,点击启动子Activity(B),子Actvity退出,返回父Activity调用顺序如下
- scala基础--for操作
- Linux 系统格式化磁盘并挂载分区
- 2549. 【NOIP2011模拟9.4】家庭作业 (StandardIO)
- SQL语句收集
- 分享一个Android封装精美、好用的菜单型PopupWindow
- poj2349 Arctic Network
- jquery基本简介与使用