文章导读:

早在JDK 1.2的版本中就提供Java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序, 当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本, 每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本.

视频与源码下载:http://edu.51cto.com/lecturer/index/user_id-9166337.html  (代码在视频的附件中)

先来用代码来演示下ThreadLocal强大特性

 // 用来来存储与线程相关的变量
public class ThreadLocDemo {
// 用来存储线程名称
private ThreadLocal<String> ts = new ThreadLocal<String>();
// 用来存储线程的ID
private ThreadLocal<Long> tl = new ThreadLocal<Long>(); // 获取当前线程的名称和ID信息
public void set() {
ts.set(Thread.currentThread().getName());
tl.set(Thread.currentThread().getId());
} public String getName() {
return ts.get();
} public Long getId() {
return tl.get();
} public static void main(String[] args) throws Exception {
// 当前线程是主线程
// System.out.println(Thread.currentThread().getName());
// System.out.println(Thread.currentThread().getId()); // 把主线程的信息存储在ThreadLocal中
final ThreadLocDemo demo = new ThreadLocDemo();
demo.set();
// 输出主线程的信息
System.out.println(demo.getName());
System.out.println(demo.getId()); // 创建一个子线程,然后用demo也存储子线程的信息
new Thread(new Runnable() {
public void run() {
// 把子线程的信息存储在ThreadLocal中
demo.set();
// 输出子线程的信息
System.out.println(demo.getName());
System.out.println(demo.getId());
}
}, "xyz").start(); Thread.sleep(1000);
// 输出主线程的信息
System.out.println(demo.getName());
System.out.println(demo.getId());
}
}

从打印结果可以看出主线程与子线程数据的存储,获取是不冲突的

main
1
xyz
9
main
1

ThreadLocal.set源码分析, 通过源码可以看出来,Local为不同的线程创建了自己的ThreadLocalMap对象.数据本质是存储在ThreadLocalMap中

 public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}

ThreadLocalMap存储结构分析

 static class ThreadLocalMap {
// 存储数据的类型是弱引用
static class Entry extends WeakReference<ThreadLocal> { Object value;
Entry(ThreadLocal k, Object v) {
super(k);
value = v;
}
}
}

ThreadLocal.get()源码分析. 其实还是先通过线程获取每个线程自己的LocalMap对象,然后从Map对象中获取数据信息

 public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
return (T)e.value;
}
return setInitialValue();
}

总结, 大家注意三点:

  • 每个线程中都有一个自己的ThreadLocalMap类对象,可以将线程自己的对象保持到其中,各管各的,线程可以正确的访问到自己的对象
  • 将一个共用的ThreadLocal静态实例作为key,将不同对象的引用保存到不同线程的ThreadLocalMap中
  • ThreadLocal 不是用来解决共享对象的多线程访问问题的, 它是用来延迟变量的生命周期,后面的事务、缓存都会用到此API

02_ThreadLocal语法与源码分析的更多相关文章

  1. 鸿蒙内核源码分析(GN应用篇) | GN语法及在鸿蒙的使用 | 百篇博客分析OpenHarmony源码 | v60.01

    百篇博客系列篇.本篇为: v60.xx 鸿蒙内核源码分析(gn应用篇) | gn语法及在鸿蒙的使用 | 51.c.h.o 编译构建相关篇为: v50.xx 鸿蒙内核源码分析(编译环境篇) | 编译鸿蒙 ...

  2. ABP源码分析六:依赖注入的实现

    ABP的依赖注入的实现有一个本质两个途径:1.本质上是依赖于Castle这个老牌依赖注入的框架.2.一种实现途径是通过实现IConventionalDependencyRegistrar的实例定义注入 ...

  3. gRPC源码分析0-导读

    gRPC是Google开源的新一代RPC框架,官网是http://www.grpc.io.正式发布于2016年8月,技术栈非常的新,基于HTTP/2,netty4.1,proto3.虽然目前在工程化方 ...

  4. 史上最全的 Redux 源码分析

    前言 用 React + Redux 已经一段时间了,记得刚开始用Redux 的时候感觉非常绕,总搞不起里面的关系,如果大家用一段时间Redux又看了它的源码话,对你的理解会有很大的帮助.看完后,在回 ...

  5. jQuery 2.0.3 源码分析 事件绑定 - bind/live/delegate/on

    事件(Event)是JavaScript应用跳动的心脏,通过使用JavaScript ,你可以监听特定事件的发生,并规定让某些事件发生以对这些事件做出响应 事件的基础就不重复讲解了,本来是定位源码分析 ...

  6. jQuery-1.9.1源码分析系列(十六)ajax——响应数据处理和api整理

    ajax在得到请求响应后主要会做两个处理:获取响应数据和使用类型转化器转化数据 a.获取响应数据 获取响应数据是调用ajaxHandleResponses函数来处理. ajaxHandleRespon ...

  7. Struts2 源码分析——DefaultActionInvocation类的执行action

    本章简言 上一章讲到关于拦截器的机制的知识点,让我们对拦截器有了一定的认识.我们也清楚的知道在执行用户action类实例之前,struts2会先去执行当前action类对应的拦截器.而关于在哪里执行a ...

  8. Struts2 源码分析——配置管理之PackageProvider接口

    本章简言 上一章讲到关于ContainerProvider的知识.让我们知道struts2是如何注册相关的数据.也知道如何加载相关的配置信息.本章笔者将讲到如何加载配置文件里面的package元素节点 ...

  9. angular源码分析:angular中脏活累活承担者之$parse

    我们在上一期中讲 $rootscope时,看到$rootscope是依赖$prase,其实不止是$rootscope,翻看angular的源码随便翻翻就可以发现很多地方是依赖于$parse的.而$pa ...

随机推荐

  1. jQuery知识点小结

    博主之前学习一段时间后做了点Demo,借此机会发出来分享,其实学jQuery只要简单看看文档即可,但有些细枝末节的东西文档会默认使用者是了解的,所以还是得系统学习系统训练:Talk is cheap, ...

  2. 64位Windows系统下32位应用程序连接MySql

    1.首先得安装“Connector/ODBC”,就是Mysql的ODBC驱动,这个是与应用程序相关的,而不是与操作系统相关的,也就是说,不管你的系统是x64还是x86,只要你的应用程序是x86的那么, ...

  3. Netweaver和CloudFoundry的服务器日志

    Netweaver 事务码SMICM,Goto->HTTP Plug-In->Server Logs: CloudFoundry 假设我部署本地应用到CloudFoundry之后,应用的状 ...

  4. UVALive 3942 Remember The Word (Tire)

    状态是DAG,因此方案用dp统计,dp[i] = sum(dp[i+len(x)]),x是以i开头的前缀且是单词,关键在于快速判断一个前缀是不是单词,可用Trie. 每一次转移的复杂度是O(maxle ...

  5. Netbackup8.0以上版本,服务端生成证书,客户端获取、更新证书方式(整理中)

    创建重发令牌 如果非主控主机已在主服务器上注册但其基于主机ID的证书不再有效,则可以重新颁发基于主机ID的证书.例如,证书在过期,被撤销或丢失时无效. 重发令牌是一种可用于重新颁发证书的令牌.它是一种 ...

  6. 小技巧:unicode RLO

    unicode 控制字符 RLO 可以将位于其后的文字翻转. 于是可以被病毒利用. 如图 重命名文件,在gpj前插入unicode RLO,之后若不小心,可能会被欺骗,误以为是jpg文件. 如果修改程 ...

  7. JsonPath 语法 与 XPath 对比

    JsonPath 语法 与 XPath 对比   XPath JSONPath Description / $ the root object/element . @ the current obje ...

  8. linux目录结构及文件管理

    Linux的目录结构: /            根分区 linux文件系统的起点 /bin           普通用户的命令,普通用户能使用 /sbin         管理员使用的命令,只有管理 ...

  9. Java的引用StrongReference、 SoftReference、 WeakReference 、PhantomReference

    1. Strong Reference StrongReference 是 Java 的默认引用实现,  它会尽可能长时间的存活于 JVM 内, 当没有任何对象指向它时 GC 执行后将会被回收 @Te ...

  10. LibreOffice Writer Comment

    选择文字段后输入:Ctrl+Alt+C可以插入评论,但会出现: unknown author 解决方法:Tools>Options>LibreOffice>User Data. Fi ...