当前位置:首页 > 科技  > 软件

ThreadLocal和InheritableThreadLocal详解

来源: 责编: 时间:2023-10-08 07:05:54 188观看
导读一、概述为了方便且更加安全的进行多线程编程,jdk引入ThreadLocal和InheritableThreadLocal两个类,以供开发人员进行多线程之间的数据传递和数据共享。InheritableThreadLocal是ThreadLocal的子类,它可以实现子线程共享

iUT28资讯网——每日最新资讯28at.com

一、概述

为了方便且更加安全的进行多线程编程,jdk引入ThreadLocal和InheritableThreadLocal两个类,以供开发人员进行多线程之间的数据传递和数据共享。InheritableThreadLocal是ThreadLocal的子类,它可以实现子线程共享父线程的变量。iUT28资讯网——每日最新资讯28at.com

二、案例介绍

ThreadLocal:iUT28资讯网——每日最新资讯28at.com

private static ThreadLocal<String> testThreadLocal = new ThreadLocal<>();/*// 创建时可重写初始化方法ThreadLocal<String> testThreadLocal = new ThreadLocal<String>(){    public Connection initialValue(){        return "zhangsan";    }};*/public static void main(String[] args) {        // 设置线程变量        testThreadLocal.set("zhangsan");        // 获取线程变量        String userName = testThreadLocal.get();        System.out.println("userName: " + userName);        // 删除线程变量        testThreadLocal.remove();        userName = testThreadLocal.get();        System.out.println("userName: " + userName);}#结果输出userName: zhangsanuserName: null
public static void main(String[] args) {        // 主线程        testThreadLocal.set("zhangsan");        System.out.println("userName0: " + testThreadLocal.get());        // 线程1        new Thread(() -> {            testThreadLocal.set("lisi");            System.out.println("userName1: " + testThreadLocal.get());        }).start();        // 线程2        new Thread(() -> {            testThreadLocal.set("wangwu");            System.out.println("userName2: " + testThreadLocal.get());        }).start();}#结果输出【线程之间变量相关隔离】userName0: zhangsanuserName1: lisiuserName2: wangwu

接下来看下set方法:iUT28资讯网——每日最新资讯28at.com

public void set(T value) {    // 获取当前线程(调用方线程:主线程、线程1......)    Thread t = Thread.currentThread();    // 当前线程作为key,获取对应的线程变量ThreadLocalMap    ThreadLocalMap map = getMap(t);    if (map != null) {        // 设置线程变量:key为当前定义的ThreadLocal实例的this引用,值为我们传入的数据        map.set(this, value);    } else {        // 第一次设置线程变量,则会创建ThreadLocalMap        createMap(t, value);    }    }

再看下get方法:iUT28资讯网——每日最新资讯28at.com

public T get() {    // 获取当前线程(调用方线程:主线程、线程1......)    Thread t = Thread.currentThread();    // 当前线程作为key,获取对应的线程变量ThreadLocalMap    ThreadLocalMap map = getMap(t);    if (map != null) {        // 值最终是存在Entry对象的value属性        ThreadLocalMap.Entry e = map.getEntry(this);        if (e != null) {            T result = (T)e.value;            return result;        }    }    // ThreadLocalMap为空,则初始化操作    return setInitialValue();} private T setInitialValue() {    // 创建ThreadLocal时可重写初始化方法    T value = initialValue();    // 获取当前线程(调用方线程:主线程、线程1......)    Thread t = Thread.currentThread();    // 当前线程作为key,获取对应的线程变量ThreadLocalMap    ThreadLocalMap map = getMap(t);    if (map != null) {        // 设置线程变量:key为当前定义的ThreadLocal实例的this引用,值为初始化方法返回的数据        map.set(this, value);     } else {        // 第一次设置线程变量,则会创建ThreadLocalMap        createMap(t, value);     }        return value;}

InheritableThreadLocal:iUT28资讯网——每日最新资讯28at.com

private static InheritableThreadLocal<String> testInheritableThreadLocal = new InheritableThreadLocal<>();    public static void main(String[] args) {        // 主线程        testInheritableThreadLocal.set("zhangsan");        System.out.println("userName0: " + testInheritableThreadLocal.get());                // 线程1        new Thread(() -> System.out.println("userName1: " + testInheritableThreadLocal.get())).start();        // 线程2        new Thread(() -> System.out.println("userName2: " + testInheritableThreadLocal.get())).start();    }#结果输出userName0: zhangsanuserName1: zhangsanuserName2: zhangsan

查看InheritableThreadLocal的源码:iUT28资讯网——每日最新资讯28at.com

public class InheritableThreadLocal<T> extends ThreadLocal<T> {     protected T childValue(T parentValue) {        return parentValue;    }       ThreadLocalMap getMap(Thread t) {       return t.inheritableThreadLocals;    }    void createMap(Thread t, T firstValue) {        t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);    }}

InheritableThreadLocal继承了ThreadLocal类型,并且重写了getMap和createMap方法,唯一的区别是:threadLocals(ThreadLocalMap类型)变成了inheritableThreadLocals(ThreadLocalMap类型)。iUT28资讯网——每日最新资讯28at.com

查看get方法:iUT28资讯网——每日最新资讯28at.com

public T get() {        Thread t = Thread.currentThread();        // 注意:InheritableThreadLocal重写了getMap方法,返回inheritableThreadLocals        ThreadLocalMap map = getMap(t);        if (map != null) {            ThreadLocalMap.Entry e = map.getEntry(this);            if (e != null) {                T result = (T)e.value;                return result;            }        }        return setInitialValue();    }

查看inheritableThreadLocals设置的地方,最终定位到java.lang.Thread#init方法:iUT28资讯网——每日最新资讯28at.com

private void init(ThreadGroup g, Runnable target, String name,  long stackSize, AccessControlContext acc, boolean inheritThreadLocals) {        if (name == null) {            throw new NullPointerException("name cannot be null");        }        this.name = name;        Thread parent = currentThread();        SecurityManager security = System.getSecurityManager();        if (g == null) {            if (security != null) {                g = security.getThreadGroup();            }            if (g == null) {                g = parent.getThreadGroup();            }        }        g.checkAccess();        if (security != null) {            if (isCCLOverridden(getClass())) {                security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);            }        }        g.addUnstarted();        this.group = g;        this.daemon = parent.isDaemon();        this.priority = parent.getPriority();        if (security == null || isCCLOverridden(parent.getClass()))            this.contextClassLoader = parent.getContextClassLoader();        else            this.contextClassLoader = parent.contextClassLoader;        this.inheritedAccessControlContext =                acc != null ? acc : AccessController.getContext();        this.target = target;        setPriority(priority);        if (inheritThreadLocals && parent.inheritableThreadLocals != null)           // 将父线程inheritableThreadLocals复制给子线程inheritableThreadLocals           // 此处可联想到:如果使用了线程池,而线程池中的线程是复用的,不会再次调用初始化方法           // 所以无法将父线程inheritableThreadLocals复制给子线程inheritableThreadLocals            this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);        this.stackSize = stackSize;        tid = nextThreadID();    }

三、注意事项

  • 使用ThreadLocal、或者InheritableThreadLocal方法时,注意及时调用remove方法进行清理。
  • 注意线程池结合InheritableThreadLocal的使用,线程池中的线程是复用的,不会再次调用初始化方法,所以无法将父线程inheritableThreadLocals复制给子线程inheritableThreadLocals。

本文链接:http://www.28at.com/showinfo-26-12355-0.htmlThreadLocal和InheritableThreadLocal详解

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: API接口脱敏:如何安全地处理敏感数据?

下一篇: Java中使用正则表达式

标签:
  • 热门焦点
  • K6:面向开发人员的现代负载测试工具

    K6:面向开发人员的现代负载测试工具

    K6 是一个开源负载测试工具,可以轻松编写、运行和分析性能测试。它建立在 Go 和 JavaScript 之上,它被设计为功能强大、可扩展且易于使用。k6 可用于测试各种应用程序,包括 Web
  • 摸鱼心法第一章——和配置文件说拜拜

    摸鱼心法第一章——和配置文件说拜拜

    为了能摸鱼我们团队做了容器化,但是带来的问题是服务配置文件很麻烦,然后大家在群里进行了“亲切友好”的沟通图片图片图片图片对比就对比,简单对比下独立配置中心和k8s作为配
  • 不容错过的MSBuild技巧,必备用法详解和实践指南

    不容错过的MSBuild技巧,必备用法详解和实践指南

    一、MSBuild简介MSBuild是一种基于XML的构建引擎,用于在.NET Framework和.NET Core应用程序中自动化构建过程。它是Visual Studio的构建引擎,可在命令行或其他构建工具中使用
  • 学习JavaScript的10个理由...

    学习JavaScript的10个理由...

    作者 | Simplilearn编译 | 王瑞平当你决心学习一门语言的时候,很难选择到底应该学习哪一门,常用的语言有Python、Java、JavaScript、C/CPP、PHP、Swift、C#、Ruby、Objective-
  • 阿里瓴羊One推出背后,零售企业迎数字化新解

    阿里瓴羊One推出背后,零售企业迎数字化新解

    作者:刘旷近年来随着数字经济的高速发展,各式各样的SaaS应用服务更是层出不穷,但本质上SaaS大多局限于单一业务流层面,对用户核心关切的增长问题等则没有提供更好的解法。在Saa
  • 华为开发者大会2023日程公开:开设鸿蒙HarmonyOS 4体验区

    华为开发者大会2023日程公开:开设鸿蒙HarmonyOS 4体验区

    IT之家 7 月 31 日消息,华为今日公布了 HDC.Together 开发者大会 2023 的详细日程。整场大会将于 8 月 4 日-6 日之间举行,届时将发布最新一代鸿蒙 H
  • 2纳米决战2025

    2纳米决战2025

    集微网报道 从三强争霸到四雄逐鹿,2nm的厮杀声已然隐约传来。无论是老牌劲旅台积电、三星,还是誓言重回先进制程领先地位的英特尔,甚至初成立不久的新
  • 2022爆款:ROG魔霸6 冰川散热系统持续护航

    2022爆款:ROG魔霸6 冰川散热系统持续护航

    喜逢开学季,各大商家开始推出自己的新产品,进行打折促销活动。对于忠实的端游爱好者来说,能够拥有一款梦寐以求的笔记本电脑是一件十分开心的事。但是现在的
  • 中关村论坛11月25日开幕,15位诺奖级大咖将发表演讲

    中关村论坛11月25日开幕,15位诺奖级大咖将发表演讲

    11月18日,记者从2022中关村论坛新闻发布会上获悉,中关村论坛将于11月25至30日在京举行。本届中关村论坛由科学技术部、国家发展改革委、工业和信息化部、国务
Top