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

ThreadLocal和InheritableThreadLocal详解

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

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

一、概述

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

二、案例介绍

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

查看get方法:oYo28资讯网——每日最新资讯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方法:oYo28资讯网——每日最新资讯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。

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

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

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

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

标签:
  • 热门焦点
Top
Baidu
map