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

ThreadLocal和InheritableThreadLocal详解

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

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

一、概述

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

二、案例介绍

ThreadLocal:MUF28资讯网——每日最新资讯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方法:MUF28资讯网——每日最新资讯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方法:MUF28资讯网——每日最新资讯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:MUF28资讯网——每日最新资讯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的源码:MUF28资讯网——每日最新资讯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类型)。MUF28资讯网——每日最新资讯28at.com

查看get方法:MUF28资讯网——每日最新资讯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方法:MUF28资讯网——每日最新资讯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中使用正则表达式

标签:
  • 热门焦点
  • 影音体验是真的强 简单聊聊iQOO Pad

    大公司的好处就是产品线丰富,非常细分化的东西也能给你做出来,例如早先我们看到了新的vivo Pad2,之后我们又在iQOO Neo8 Pro的发布会上看到了iQOO的首款平板产品iQOO Pad。虽
  • 6月安卓手机性能榜:vivo/iQOO霸占旗舰排行榜前三

    2023年上半年已经正式过去了,我们也迎来了安兔兔V10版本,在新的骁龙8Gen3和天玑9300发布之前,性能榜的榜单大体会以骁龙8Gen2和天玑9200+为主,至于那颗3.36GHz的骁龙8Gen2领先
  • 之家push系统迭代之路

    前言在这个信息爆炸的互联网时代,能够及时准确获取信息是当今社会要解决的关键问题之一。随着之家用户体量和内容规模的不断增大,传统的靠"主动拉"获取信息的方式已不能满足用
  • 如何通过Python线程池实现异步编程?

    线程池的概念和基本原理线程池是一种并发处理机制,它可以在程序启动时创建一组线程,并将它们置于等待任务的状态。当任务到达时,线程池中的某个线程会被唤醒并执行任务,执行完任
  • 微信语音大揭秘:为什么禁止转发?

    大家好,我是你们的小米。今天,我要和大家聊一个有趣的话题:为什么微信语音不可以转发?这是一个我们经常在日常使用中遇到的问题,也是一个让很多人好奇的问题。让我们一起来揭开这
  • Temu起诉SHEIN,跨境电商战事升级

    来源 | 伯虎财经(bohuFN)作者 | 陈平安日前据外媒报道,拼多多旗下跨境电商平台Temu正对竞争对手SHEIN提起新诉讼,诉状称Shein&ldquo;利用市场支配力量强迫服装厂商与之签订独家
  • Android 14发布:首批适配机型公布

    5月11日消息,谷歌在今天凌晨举行了I/O大会,本次发布会谷歌带来了自家的AI语言模型PaLM 2、谷歌Pixel Fold折叠屏、谷歌Pixel 7a手机,同时发布了Androi
  • 引领旗舰级影像能力向中端机普及 OPPO K11 系列发布 1799 元起

    7月25日,OPPO正式发布K系列新品—— OPPO K11 。此次 K11 在中端手机市场长期被忽视的影像板块发力,突破性地搭载索尼 IMX890 旗舰大底主摄,支持 OIS
  • 质感不错!OPPO K11渲染图曝光:旗舰IMX890传感器首次下放

    一直以来,OPPO K系列机型都保持着较为均衡的产品体验,历来都是2K价位的明星机型,去年推出的OPPO K10和OPPO K10 Pro两款机型凭借各自的出色配置,堪称有
Top