并发编程-ThreadLocal

·  阅读 1456

并发编程-ThreadLocal

说在前面的话

今天的文章很短,但是很经典,值得你仔细阅读每一个文字.........

正如我开篇所说,我们要整理一些java并发编程的学习文档,这一篇就是第七篇:ThreadLocal。主要聊聊ThreadLocal本质。希望对你有帮助。

开整

故事理解

来看一个场景。

​ 有三个小伙伴大锤、大黄和大牛,搬砖到半夜,准备去洗澡按摩,来到心仪的地方,领了手牌,大锤的手牌是007,大黄的手牌是008,大牛的手牌是009。 进入更衣区,大锤使用007手牌打开8007号柜子,大黄使用008手牌打开8008号柜子,大牛使用009号手牌打开8009号柜子。

​ 洗好澡,换好衣服,大锤使用007号手牌进入6007号包间,大黄使用007号手牌进入了6008号房间,大牛使用009号手牌进入了6009号房间。

​ 嗯!。。。。。。之后每个人用自己的手牌也找了对应的技师。。。。。一天的疲惫就是消除。。。。

场景说完,稍微解释一下:

我们说:换衣服,洗澡,进包间,按摩就是一套流程,就是一个线程。其中每一个环节(换衣服,洗澡,进包间,按摩)都是一个具体的方法。 大锤,大黄,大牛都是走了同一套流程,也就是同一个线程。线程中的每一个环节他们都是使用自己的手牌获取不同的资源(柜子,包间,技师)为自己服务。

我们可以说手牌(或者他们本人)就是一个ThreadLocal对象。 线程中维护一个ThreadLocalMap,就好比更衣间的一排柜子,每个ThreadLocal都可以根据自身对象保存一些数据到这个Map中,就好比他们每个人可以根据自己的手牌在一排柜子中找到自己的柜子,并且放入自己的衣服。走的时候依然可以根据自己的手牌从自己的柜子中取出自己的衣服。

看图理解:

1654853097615.png

故事到程序

将上一小节的图解和说明使用程序来实现。

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());
   }
}
复制代码

执行结果:

1654857740842.png

说明

ThreadLocal是Thread的局部变量,用于编多线程程序,对解决多线程程序的并发问题有一定的启示作用。

上面这句话是百度百科的说明。

ThreadLocal本身只是一个普通的对象。没有什么特殊的。

我们要研究ThreadLocal就先要看看Thread类,在Thread类中有一个成员变量ThreadLocalMap:

1654858338401.png

在ThreadLocal的set方法中有如下的程序:

1654859706956.png

通过这个源码,我们会发现,当我们调用ThreadLocal的set方法的时候,会先去尝试获取一个ThreadLocalMap对象,而这个对象就是直接获取当前线程的threadlocals属性。如果获取到就调用其set方法,并且将当前的ThreadLocal对象作为key,如果获取不到就调用createMap,而在createMap就是直接new了一个ThreadLocalMap对象,当然了当前的ThreadLocal对象依然是key。

所以呢:怎么理解呢set方法呢?看图:

1654860151827.png 也就是说在每个Thread中都有一个ThreadLocalMap,这个Map的key都是ThreadLocal对象。ThreadLocal的set方法就是给当前的线程的ThreadLocalMap中设置一组映射,而这组映射的key就是调用这个set方法的ThreadLocal对象本身。 每个一Thread中可以设置多个ThreadLocal,一个ThreadLocal对象也可以在多个Thread中添加数据,像这样: 1654860411904.png 所以,不知道你理解没理解呢?

顺便看看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的情况就是这样了。

还有其他的并发编程相关的内容,我回持续更新,欢迎关注。

我是”起点编程“的"戴着假发的程序员" 欢迎关注…欢迎评论。。。。。

起点编程-是你我的未来…

分类:
后端
标签:
收藏成功!
已添加到「」, 点击更改