- 使用 Spring Initializr 创建 Spring Boot 应用程序
- 在Spring Boot中配置Cassandra
- 在 Spring Boot 上配置 Tomcat 连接池
- 将Camel消息路由到嵌入WildFly的Artemis上
今天的文章很短,但是很经典,值得你仔细阅读每一个文字…
正如我开篇所说,我们要整理一些java并发编程的学习文档,这一篇就是第七篇:ThreadLocal。主要聊聊ThreadLocal本质。希望对你有帮助。
来看一个场景。
有三个小伙伴大锤、大黄和大牛,搬砖到半夜,准备去洗澡按摩,来到心仪的地方,领了手牌,大锤的手牌是007,大黄的手牌是008,大牛的手牌是009。 进入更衣区,大锤使用007手牌打开8007号柜子,大黄使用008手牌打开8008号柜子,大牛使用009号手牌打开8009号柜子。
洗好澡,换好衣服,大锤使用007号手牌进入6007号包间,大黄使用007号手牌进入了6008号房间,大牛使用009号手牌进入了6009号房间。
嗯!。。。。。。之后每个人用自己的手牌也找了对应的技师。。。。。一天的疲惫就是消除。。。。
场景说完,稍微解释一下:
我们说:换衣服,洗澡,进包间,按摩就是一套流程,就是一个线程。其中每一个环节(换衣服,洗澡,进包间,按摩)都是一个具体的方法。 大锤,大黄,大牛都是走了同一套流程,也就是同一个线程。线程中的每一个环节他们都是使用自己的手牌获取不同的资源(柜子,包间,技师)为自己服务。
我们可以说手牌(或者他们本人)就是一个ThreadLocal对象。 线程中维护一个ThreadLocalMap,就好比更衣间的一排柜子,每个ThreadLocal都可以根据自身对象保存一些数据到这个Map中,就好比他们每个人可以根据自己的手牌在一排柜子中找到自己的柜子,并且放入自己的衣服。走的时候依然可以根据自己的手牌从自己的柜子中取出自己的衣服。
看图理解:
将上一小节的图解和说明使用程序来实现。
package com.st.demo;
/**
* @author 戴着假发的程序员
*/
public class ThreadLocalTest {
// 准备三个ThreadLocal对象,分别是大锤、大黄和大牛
static ThreadLocal dachui = new ThreadLocal();
static ThreadLocal dahuang = new ThreadLocal();
static ThreadLocal daniu = new ThreadLocal();
public static void main(String[] args) {
// 开启一个洗澡的线程
new Thread(()->{
tuoyifu();// 先脱衣服放入自己的柜子里,去洗澡
chuanyifu();// 洗好澡,从自己的柜子中取出自己的衣服
},"洗澡-按摩").start();
}
// 脱衣服放入柜子的流程
public static void tuoyifu(){
dachui.set("8007号柜子-大锤的阿玛尼");
dahuang.set("8008号柜子-大黄的美特斯邦威");
daniu.set("8009号柜子-大牛的奔驰大衣");
}
// 从柜子中取出衣服的流程
public static void chuanyifu(){
System.out.println("大锤 取出 " + dachui.get());
System.out.println("大黄 取出 " + dahuang.get());
System.out.println("大牛 取出 " + daniu.get());
}
}
执行结果:
ThreadLocal是Thread的局部变量,用于编多线程程序,对解决多线程程序的并发问题有一定的启示作用。
上面这句话是百度百科的说明。
ThreadLocal本身只是一个普通的对象。没有什么特殊的。
我们要研究ThreadLocal就先要看看Thread类,在Thread类中有一个成员变量ThreadLocalMap:
在ThreadLocal的set方法中有如下的程序:
通过这个源码,我们会发现,当我们调用ThreadLocal的set方法的时候,会先去尝试获取一个ThreadLocalMap对象,而这个对象就是直接获取当前线程的threadlocals属性。如果获取到就调用其set方法,并且将当前的ThreadLocal对象作为key,如果获取不到就调用createMap,而在createMap就是直接new了一个ThreadLocalMap对象,当然了当前的ThreadLocal对象依然是key。
所以呢:怎么理解呢set方法呢?看图:
也就是说在每个Thread中都有一个ThreadLocalMap,这个Map的key都是ThreadLocal对象。ThreadLocal的set方法就是给当前的线程的ThreadLocalMap中设置一组映射,而这组映射的key就是调用这个set方法的ThreadLocal对象本身。 每个一Thread中可以设置多个ThreadLocal,一个ThreadLocal对象也可以在多个Thread中添加数据,像这样:
所以,不知道你理解没理解呢?
顺便看看get方法和remove方法呢
public class ThreadLocal{
//....
public T get() {
// 获取当前线程
Thread t = Thread.currentThread();
// 取出当前线程中的ThreadLocalMap threadLocals;
ThreadLocalMap map = getMap(t);
if (map != null) {
// 通过当前对象取出对应的Entry对象
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
// 返回取出的结果
return result;
}
}
return setInitialValue();
}
public void remove() {
// 获取当前线程中的ThreadLocalMap threadLocals;
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
// 根据当前对象删除对应的数据
m.remove(this);
}
//.......
}
呕吼!!!
关于ThreadLocal的情况就是这样了。
还有其他的并发编程相关的内容,我回持续更新,欢迎关注。
我是”起点编程“的"戴着假发的程序员" 欢迎关注…欢迎评论。。。。。
起点编程-是你我的未来…
我正在尝试在多线程环境中实现某种累积逻辑;我想知道没有 lock 和 synchronized 关键字是否有更好/更快的方法来做到这一点?以下是我当前的代码: public class Concurr
我需要帮助构建一个实现信号量的监视器,简单的 C 示例就可以。 这是为了证明可以在任何可以使用信号量的地方使用监视器。 最佳答案 如果您说允许使用互斥锁/condvars,请检查: #include
我已经构建了一些返回部分产品目录的 ajax,并且我正在尝试将 xml 输出到文档中,到目前为止,这是我所拥有的: $("#catalog").append("Item NamePriceDe
很抱歉,如果我的问题之前已经被问过,或者它太明显了,但我真的需要澄清这一点。感谢您的帮助。 在多用户界面中,如果来自不同用户的相同事务同时到达服务器,会发生什么? 我有下一张表: create tab
这可能是一个愚蠢的问题,但是这个程序的输出(它的方式)可以为零吗? public class Test2{ int a = 0; AtomicInteger b = new Atomi
假设我本地主机上的一个网站处理每个请求大约需要 3 秒。这很好,正如预期的那样(因为它在幕后进行了一些奇特的网络)。 但是,如果我在选项卡(在 firefox 中)中打开相同的 url,然后同时重新加
我对 MongoDB 的读锁定有点困惑。单个集合可以支持多少个并发读取操作? 最佳答案 如 tk 给出的链接中所写:http://www.mongodb.org/pages/viewpage.acti
如果有四个并发的 CUDA 应用程序在一个 GPU 中竞争资源会发生什么这样他们就可以将工作卸载到图形卡上了? Cuda Programming Guide 3.1 提到那里 某些方法是异步的: 内核
👊上次的百度面试遇到了关于spark的并发数的问题,今天我们就来将这些问题都一并解决一下,图画的的有点丑,还行大家见谅,百度实习的问题我放在了下面的链接👇: 链接: 2022百度大数据开发工程师实
我对 Groovy 线程有疑问。 我的任务是以某种方式翻译给定目录中的每个文件 并将生成的输出放在其他目录中的文件中。 我编写了以下代码,该代码有效: static def translateDir(
Java中的同步和锁定有什么区别? 最佳答案 synchronized是语言关键字;锁是对象。 当一个方法或代码块被标记为同步时,您是说该方法或代码块必须先获得某个锁对象(可以在同步的语法中指定)才能
我需要创建一个能够同时处理来自客户端的多个请求的并发 RPC 服务器。 使用 rpcgen linux编译器(基于sun RPC),不支持-A为并发服务器创建 stub 的选项。 (-A 选项在 so
System.out.println("Enter the number of what you would like to do"); System.out.println("1 = Manuall
我正在将我的应用程序移植到 iOS 8.0 并注意到 UIAlertView 已被弃用。 所以我改变了使用 UIAlertController 的方法。这在大多数情况下都有效。 除了,当我的应用程序打
我正在逐行同时读取两个文本文件。 我特别想做的是当lineCount在每个线程上都是相同的我想看看扫描仪当前正在读取的字符串。 我环顾四周寻找可以实现的某些模式,例如 Compare and Swap
我正在阅读 Java Concurrency in Practice .在章节中断政策部分 取消和关闭 它提到 A task should not assume anything about the
我正在尝试学习线程,互斥等的基础知识。遵循here的文档和示例。在下面的代码中,我得到预期的输出。问题: 想确认我是否有任何陷阱?我们如何改善下面的代码? 我的线程在哪一行尝试获取互斥锁或正在等待互斥
并发是指两个任务在不同的线程上并行运行。但是,异步方法并行运行,但在同一个线程上。这是如何实现的?另外,并行性怎么样? 这三个概念有什么区别? 最佳答案 并发和并行实际上与您正确推测的原理相同,两者都
以此ConcurrentDouble类定义为例: public class ConcurrentDouble { public double num = 0; public void subt
在得知并发确实增加了许多人的吞吐量后,我一直计划在项目中使用并发。现在我在多线程或并发方面还没有做太多工作,因此决定在实际项目中使用它之前学习并进行简单的概念验证。 以下是我尝试过的两个示例: 1.
我是一名优秀的程序员,十分优秀!