java多线程之threadlocal的原理分析

【Java多线程】ThreadLocal 原理分析与使用场景 ThreadLocal通过为每个线程创建变量副本来实现线程隔离,其核心是ThreadLocalMap静态内部类。ThreadLocal变量被private static修饰,各线程独立修改自身副本而不影响其他线程。ThreadLocalMap使用弱引用作为key存储线程变量,可能导致内存泄漏需注意。使用时需重写initialValue()方法初始化值,并通过get()、set()操作线程副本。典型应用场景包括线程独享计数器等。子线程无法继承父线程数据,可用InheritableThreadLocal解决。使 阅读详情

jdk1.2版本就有解决多线程并发的工具类,threadlocal类本质上以空间换时间,让每一个线程拥有一份共享变量的副本,然后这样就没有多线程并发的问题,每一个线程都各自修改自己变量副本,互不影响,

ThreadLocal的属性

ThreadLocal属性非常简单就是nextHashCode, 还有一个魔数HASH_INCREMENT变量,它是每次增加的这个固定的 数,就得到下一个Hash值,下面代码官方注释说明相比于连续的递增的hashcode,每次增加 固定魔数,对于2的n次方幂的数组效率更优,至于为什么选取加这个魔数,这个跟斐波那契数列有关,感兴趣可以另外搜索相关资料研究

private final int threadLocalHashCode = nextHashCode();

/**
 * The next hash code to be given out. Updated atomically. Starts at
 * zero.
 */
private static AtomicInteger nextHashCode =
    new AtomicInteger();
/**
 * The difference between successively generated hash codes - turns
 * implicit sequential thread-local IDs into near-optimally spread
 * multiplicative hash values for power-of-two-sized tables.
 */
private static final int HASH_INCREMENT = 0x61c88647;
复制代码

ThreadLocal的set方法

get set方法是了解threadLocal的核心原理的方法,

  • 首先获取当前线程,
  • 获取Thread的内部对象ThreadLocalMap的变量,
  • 如果ThreadLocalMap变量为空,则创建ThreadLocalMap对象, 注意这里的参数this是threadLocal的事例
  • 如果ThreadLocalMap变量不为空,则直接设置值
public void set(T value) {
   //获取当前线程
    Thread t = Thread.currentThread();
    //获取ThreadLocalMap对象
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        //设置值
        map.set(this, value);
    } else {
        //创建
        createMap(t, value);
    }
}
//创建ThreadLocalMap对象
void createMap(Thread t, T firstValue) {
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}
复制代码

ThreadLocalMap类成员变量

从下面可以看到ThreadLocalMap的数组的对象是Entry对象,它是继承了WeakReference这个,初始化Entry对象时,调用了父类的构造函数,也就是Entry对象中k是弱引用,而上面创建该对象时,传入的参数就是ThreadLocal对象的this指针,所以放入ThreadLocalMap中Entry 对象中ThreadLocal时弱引用,

static class ThreadLocalMap {
    /**
     * The entries in this hash map extend WeakReference, using
     * its main ref field as the key (which is always a
     * ThreadLocal object).  Note that null keys (i.e. entry.get()
     * == null) mean that the key is no longer referenced, so the
     * entry can be expunged from table.  Such entries are referred to
     * as "stale entries" in the code that follows.
     */
    static class Entry extends WeakReference<ThreadLocal<?>> {
        /** The value associated with this ThreadLocal. */
        Object value;

        Entry(ThreadLocal<?> k, Object v) {
            super(k);
            value = v;
        }
    }
    /**
     * The initial capacity -- MUST be a power of two.
     */
    private static final int INITIAL_CAPACITY = 16;
    /**
     * The table, resized as necessary.
     * table.length MUST always be a power of two.
     */
    private Entry[] table;
    /**
     * The number of entries in the table.
     */
    private int size = 0;
    /**
     * The next size value at which to resize.
     */
    private int threshold; // Default to 0
复制代码

Thread和ThreadLocalMap以及ThreadLocal之间的关系如下:

image.png

从上图可以看出ThreadLocalMap中key是ThreadLocal对象,value就是保存的变量值,这两个构成一个Entry对象,设置到ThreadLocalMap中,解决冲突方法是开发地址法,即往右面偏移,而HashMap则是拉链法,这只是两种其中一点不同,其他的可以继续往下看。

  • 首先去key的threadLocalHashCode值与(len-1)做&运算,然后得到具体落到哪一个桶上, 如果产生碰撞,则通过开放地址法,index加1往后偏移一个桶地址,如果找到key等于k, 则将新value替换旧值后返回。
  • 如果查询过程中key为null,此时会调用replaceStaleEntry替换老的Entry.
  • 如果i的位置为空,则创建一个新的Entry,放到i的位置,size加1.
  • 调用cleanSomeSlots清除[i,size)区间一些槽位, 如果数组的长度大于threshold(即数组的2/3),则调用rehas进行扩容.
private void set(ThreadLocal<?> key, Object value) {

    // We don't use a fast path as with get() because it is at
    // least as common to use set() to create new entries as
    // it is to replace existing ones, in which case, a fast
    // path would fail more often than not.
    Entry[] tab = table;
    int len = tab.length;
    int i = key.threadLocalHashCode & (len-1);
    
    for (Entry e = tab[i];
         e != null;
         e = tab[i = nextIndex(i, len)]) {
        ThreadLocal<?> k = e.get();

        if (k == key) {
            e.value = value;
            return;
        }

        if (k == null) {
            replaceStaleEntry(key, value, i);
            return;
        }
    }
    
    tab[i] = new Entry(key, value);
    int sz = ++size;
    if (!cleanSomeSlots(i, sz) && sz >= threshold)
        rehash();
}
复制代码

接下来看下replaceStaleEntry是如果替换老的Entry。

  • 首先,以上面hash地址&(len-1)得出的位置i开始, 从后往前找,找到Entry不为空,但是Entry的key为空的(这样就是会造成内存泄漏的数据),slotToExpunge标记一个index,这样[slotToExpunge,i]这个就是需要清理的索引区间。
  • 从staleSlot的位置后面一个位置,开始从前往后遍历,如果找到这个key,我们可以将这个Entry交换到staleSlot的位置,
  • 如果脏数据的开始位置和slotToExpunge的索位置相等,则slotToExpunge索引赋值为从上一步从前往后找到第一个key相等的位置的索引.然后调用expungeStaleEntry从staleSlot开始清除脏数据,最后调用cleanSomeSlots启发式扫描清除某些槽位。
  • 如果没有清理的槽位,并且size大于threshod(即size的2/3).则进行rehash进行扫描全部数组进行清理过期数据,如果还是threshod的3/4,则通过resize进行扩容。
private void replaceStaleEntry(ThreadLocal<?> key, Object value,
                               int staleSlot) {
    Entry[] tab = table;
    int len = tab.length;
    Entry e;

    // Back up to check for prior stale entry in current run.
    // We clean out whole runs at a time to avoid continual
    // incremental rehashing due to garbage collector freeing
    // up refs in bunches (i.e., whenever the collector runs).
    int slotToExpunge = staleSlot;
    for (int i = prevIndex(staleSlot, len);
         (e = tab[i]) != null;
         i = prevIndex(i, len))
        if (e.get() == null)
            slotToExpunge = i;

    // Find either the key or trailing null slot of run, whichever
    // occurs first
    for (int i = nextIndex(staleSlot, len);
         (e = tab[i]) != null;
         i = nextIndex(i, len)) {
        ThreadLocal<?> k = e.get();

        // If we find key, then we need to swap it
        // with the stale entry to maintain hash table order.
        // The newly stale slot, or any other stale slot
        // encountered above it, can then be sent to expungeStaleEntry
        // to remove or rehash all of the other entries in run.
        if (k == key) {
           //交换位置
            e.value = value;
            tab[i] = tab[staleSlot];
            tab[staleSlot] = e;

            // Start expunge at preceding stale entry if it exists
            if (slotToExpunge == staleSlot)
                slotToExpunge = i;
            cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);
            return;
        }

        // If we didn't find stale entry on backward scan, the
        // first stale entry seen while scanning for key is the
        // first still present in the run.
        if (k == null && slotToExpunge == staleSlot)
            slotToExpunge = i;
    }

    // If key not found, put new entry in stale slot
    tab[staleSlot].value = null;
    tab[staleSlot] = new Entry(key, value);

    // If there are any other stale entries in run, expunge them
    if (slotToExpunge != staleSlot)
        cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);
}
复制代码

staleSlot是已知key为空的Entry的索引, 从staleSlot开始从前往后搜索,

  • 如果key为空,则设置清设置Entry的value为null。并且设置对应位置为空,如果
  • 如果key不为空,并且i位置和hash&(len-1)不相等,说明这是通过开发地址法放进来的元素,则通过rehash,循环直到找一个hash&(len-1)的位置为空,并把它放到这个位置(这里这这一步主要是解决减少hash碰撞产生,使得查询时间复杂度为 O(1)).
private int expungeStaleEntry(int staleSlot) {
    Entry[] tab = table;
    int len = tab.length;

    // expunge entry at staleSlot
    tab[staleSlot].value = null;
    tab[staleSlot] = null;
    size--;
    // Rehash until we encounter null
    Entry e;
    int i;
    for (i = nextIndex(staleSlot, len);
         (e = tab[i]) != null;
         i = nextIndex(i, len)) {
        ThreadLocal<?> k = e.get();
        if (k == null) {
            e.value = null;
            tab[i] = null;
            size--;
        } else {
            int h = k.threadLocalHashCode & (len - 1);
            if (h != i) {
                tab[i] = null;

                // Unlike Knuth 6.4 Algorithm R, we must scan until
                // null because multiple entries could have been stale.
                while (tab[h] != null)
                    h = nextIndex(h, len);
                tab[h] = e;
            }
        }
    }
    return i;
}
复制代码

这里就是搜素索引i(即expungeStaleEntry函数返回索引的位置,即staleSlot位置后第一个Entry为空的位置,即不是脏数据的索引),n就是tab的length,从i开始往后遍历,如果Entry不为空,但是key为空,保存len,赋值removed变量为true,然后调用expungeStaleEntry再次 清除脏数据,然后将n缩减一半的长度,重新探索,直至0为止。

private boolean cleanSomeSlots(int i, int n) {
    boolean removed = false;
    Entry[] tab = table;
    int len = tab.length;
    do {
        i = nextIndex(i, len);
        Entry e = tab[i];
        if (e != null && e.get() == null) {
            n = len;
            removed = true;
            i = expungeStaleEntry(i);
        }
    } while ( (n >>>= 1) != 0);
    return removed;
}
复制代码
  • 扫描全部数据进行清理过期数据,
  • size 大于 threshod的3/4,则调用resize进行扩容。
private void rehash() {
    expungeStaleEntries();

    // Use lower threshold for doubling to avoid hysteresis
    if (size >= threshold - threshold / 4)
        resize();
}
复制代码

ThreadLocal resize进行扩容

ThreadLocal的扩容机制,是将申请原先长度乘以2的数组,然后重新计算hash值,然后放入新的数组中即可,然后重新计算扩容阈值。

private void resize() {
    Entry[] oldTab = table;
    int oldLen = oldTab.length;
    int newLen = oldLen * 2;
    Entry[] newTab = new Entry[newLen];
    int count = 0;

    for (int j = 0; j < oldLen; ++j) {
        Entry e = oldTab[j];
        if (e != null) {
            ThreadLocal<?> k = e.get();
            if (k == null) {
                e.value = null; // Help the GC
            } else {
                int h = k.threadLocalHashCode & (newLen - 1);
                while (newTab[h] != null)
                    h = nextIndex(h, newLen);
                newTab[h] = e;
                count++;
            }
        }
    }

    setThreshold(newLen);
    size = count;
    table = newTab;
}
复制代码

ThreadLocal get进行获取值

  • 首先获取Thread的threadLocalMap对象,然后通过getEntry方法获Entry对象,
  • 然后获取Entry不为空,则直接返回,
public T get() {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
    return setInitialValue();
}
复制代码

*首先通过key的threadLocalHashCode&(len-1),定位到对应的桶,

  • 如果key相等,说明已经找到该元素,直接返回
  • 如果key不等,则开发地址法,调用getEntryAfterMiss继续往查找。
private Entry getEntry(ThreadLocal<?> key) {
    int i = key.threadLocalHashCode & (table.length - 1);
    Entry e = table[i];
    if (e != null && e.get() == key)
        return e;
    else
        return getEntryAfterMiss(key, i, e);
}
复制代码
  • 继续从i的位置往后搜索直到entry为空时停止
  • 如果遇到k为空null时,则expungeStaleEntry进行清理过期数据
  • 如果循环结束还咩有找到,则直接返回null结束
private Entry getEntryAfterMiss(ThreadLocal<?> key, int i, Entry e) {
    Entry[] tab = table;
    int len = tab.length;

    while (e != null) {
        ThreadLocal<?> k = e.get();
        if (k == key)
            return e;
        if (k == null)
            expungeStaleEntry(i);
        else
            i = nextIndex(i, len);
        e = tab[i];
    }
    return null;
}
复制代码

ThreadLocal的remove删除值

  • 首先还是通过threadLocalHashCode&(len-1)定位对应的数组索引i,

*从i开始从前往后搜索,知道key相等,然后删除Entry,然后执行expungeStaleEntry进行 一次过期数据的清理结束

private void remove(ThreadLocal<?> key) {
    Entry[] tab = table;
    int len = tab.length;
    int i = key.threadLocalHashCode & (len-1);
    for (Entry e = tab[i];
         e != null;
         e = tab[i = nextIndex(i, len)]) {
        if (e.get() == key) {
            e.clear();
            expungeStaleEntry(i);
            return;
        }
    }
}
复制代码

总结
今天主要是对ThreadLocal的set get remove等重要方法进行一个详细的分析,也对ThreadLocal的解决Hash冲突的方法,key的弱引用,扩容、探测清理和启发式清理过期元素有了一个清理的认识。


作者:xjz1842
链接:https://juejin.cn/post/7005091348118241288
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

CentOS7环境下搭建 rsyslog 日志服务器,rsyslog+loganalyzer 1.系统环境部署 ip hostname 192.168.200.182 web 192.168.200.184 rsyslog-mysql 关闭防火墙、selinux、下载epel源 [root@web ~]# systemctl status firewalld.service ● firewalld.service - firewalld - dynamic firewall daemon Loaded: loaded (/usr/lib/systemd/system/f 阅读详情

相关推荐

ZYNQ-7035+HMCAD1511高速数据采集系统设计

高速数据采集是电子测量、雷达信号处理与通信基带验证的核心技术基础,其性能瓶颈常集中于采样率、通道同步性与实时处理能力。基于ADC采样原理与SoC异构架构,高带宽、低抖动时钟链路与FPGA+ARM协同处理成为突破关键。ZYNQ-7035凭借275K逻辑单元与千级DSP资源,显著提升LVDS数据流吞吐与片上滤波/触发等实时算法部署能力;HMCAD1511则以1GSPS四通道同步采样和8位分辨率,满足示波器级动态范围需求。该组合广泛应用于嵌入式信号采集平台开发、教学实验系统构建及国产化仪器原型验证。

weixin_28939623的博客 261

【Java】ThreadLocal原理

每个线程都会有属于自己的本地内存,在堆(也就是上图的主内存)中的变量在被线程使用的时候会被复制一个副本线程的本地内存中,当线程修改了共享变量之后就会通过。​ 很明显,在多线程的场景下,当有多个线程对共享变量进行修改的时候,就会出现线程安全问题,即数据不一致问题。类,来修饰共享变量,使每个线程都单独拥有一份共享变量,这样就可以做到线程之间对于共享变量的隔离问题。实例中的,但实际上不是的,这种说法只是让我们更好的理解。生命周期长的线程可以理解为:线程池的核心线程。的线程一直持续运行如线程池中的线程,那么这个。

qq_44544908的博客 1232

stm32f103c8t6的中文字库

stm32的成熟中文字库,上手即用,操作简单

nbbskk的博客 3653

java之ThreadLocal原理总结

前言 多线程访问同一个共享变量时特别容易出现并发问题,特别是在多个线程需要对一个 共享变量进行写入时。为了保证线程安全,一般使用者在访问共享变量时需要进行适当的同步同步的措施一般是加锁,这就需要使用者对锁有一定的了解,这显然加重了使用者的 负担。那么有没有一种方式可以做到,当创建一个变量后,每个线程对其进行访问的时候访问的是自己线程的变量呢?其实 ThreadLocal就可以做这件事情,虽然 ThreadLocal并不是为了解决这个问题而出现的。 ThreadLocal简介和使用 ThreadLocal是

俩只猴的博客 1988

避坑指南:ZYNQ平台上AXI 1G/2.5G Ethernet Subsystem实现IEEE1588的5个关键点

本文详细解析了在ZYNQ平台上使用AXI 1G/2.5G以太网子系统实现IEEE1588精密时间协议(PTP)的5个关键避坑点。从硬件选型、Vivado工程配置到Linux驱动适配,提供了实战经验与优化技巧,帮助工程师在工业自动化、电力系统等场景中实现纳秒级时间同步。

weixin_30687051的博客 232

Vitis开发环境下的双核ARM通信:Hello World背后的AMP架构解析

本文深入解析了Vitis开发环境下ZYNQ双核ARM Cortex-A9处理器的AMP架构与通信机制。通过详细的硬件配置、内存分配和核间通信实现步骤,展示了如何构建高效的双核Hello World系统,为嵌入式系统开发者提供了实用的开发指南和性能优化技巧。

weixin_29162439的博客 218

Java ThreadLocal 原理详解及使用

在调用 ThreadLocal 的 remove 方法时,它会获取当前线程的 ThreadLocalMap 对象,并从中删除该线程对应的变量副本。ThreadLocal 是一个本地线程变量,它为每个线程提供了一个独立的变量副本,使得每个线程只能访问自己的变量。例如,当多个线程访问同一个变量时,我们可以将该变量封装到每个线程中,使得每个线程只能访问自己的变量,避免了线程间的竞争。线程池中的线程是可以重用的,因此当线程被重用时,ThreadLocal 存储的变量可能会出现错误。

兴趣是最好的老师,勤能补拙 887

Win11笔记本BIOS设置避坑大全:Secure Boot、RST、UEFI引导,一次讲清

本文详细解析了Win11笔记本BIOS设置中的关键问题,包括Secure Boot、Intel RST和UEFI引导的配置方法,帮助用户避开双系统安装中的常见陷阱。特别针对不同品牌笔记本的BIOS界面差异,提供了实用的操作指南和优化建议,确保系统兼容性和启动效率。

weixin_29251131的博客 688

Java ThreadLocal原理

概述 threadlocal是一个线程内部的存储类,可以在指定线程内存储数据,数据存储以后,只有指定线程可以得到存储数据。 多线程访问同一个共享变量的时候容易出现并发问题,特别是多个线程对一个变量进行写入的时候,为了保证线程安全,一般使用者在访问共享变量的时候需要进行额外的同步措施才能保证线程安全性。ThreadLocal是除了加锁这种同步方式之外的一种保证一种规避多线程访问出现线程不安全的方法,当我们在创建一个变量后,如果每个线程对其进行访问的时候访问的都是线程自己的变量这样就不会存在线程不安全问题。

jiangwayne的博客 687

LPDDR5 学习笔记08:电气参数设计要求

本文详细阐述了LPDDR5内存接口的关键电气规范和时序要求。主要内容包括:1)绝对最大额定值限制及长期工作可靠性说明;2)差分时钟信号(CK/WCK)的输入电压、转换速率和交叉点电压规范;3)单端时钟信号的定义和测量方法;4)时钟周期、抖动(周期抖动、相邻周期抖动)和累积误差的精确计算方法;5)片选信号在同步/异步模式下的接收器规范;6)命令地址信号和数据信号的接收器掩模定义及脉冲宽度要求。所有参数均严格定义了测量条件和合规标准,为LPDDR5接口设计提供了完整的电气规范参考。

一只豌豆象的博客 1176

2026年医疗AI的可信革命全栈实现(上)

医疗AI可信化:贝叶斯网络与向量数据库的协同架构 本文探讨2026年医疗AI发展的关键转折点——从追求生成能力转向构建可信决策系统。核心观点认为,医疗AI下一阶段的竞争焦点在于不确定性量化和错误传播约束,而非单纯的问答流畅度。研究提出以Python为开发语言、结合向量数据库与贝叶斯网络的混合架构: 技术分层 语言层(LLM):处理自然语言交互与工具调用 证据层(Milvus/Qdrant):实现可审计的临床知识检索 概率层(pgmpy/PyMC):执行贝叶斯推理与风险路由 治理层:确保权限控制与人工复核机制

AllenLV的博客 1151

Java并发编程(七)—ThreadLocal的原理及应用详解

ThreadLocal 是 Java 中的一种特殊机制,它为每个线程提供了一个独立的变量副本,主要用于解决多线程环境下的线程安全问题通过 ThreadLocal,每个线程可以拥有自己的变量副本,从而避免了线程间的数据竞争和同步问题。

echola_mendes的博客 1858

【AI大模型】角色设定:给模型定身份的高效使用方法

摘要: AI大模型角色设定(RolePrompting)是提示词工程的核心优化技巧,通过赋予模型特定职业、领域和风格约束,显著提升输出专业度与适配性。文章系统拆解了角色设定的原理、万能公式(领域+身份+技能+风格+场景)、三级分层写法(基础/进阶/专家),并提供10类高频场景的模板。通过无角色与有角色输出的对比实验(Python代码量化验证),证明角色设定可使模型综合得分提升35%以上,尤其优化场景适配度与风格统一性。该技巧作为高阶提示词(如CoT、Few-Shot)的前置模块,能以零成本实现AI输出的专业

unber的博客 42

Java多线程编程-(8)-多图深入分析ThreadLocal原理

前几篇:Java多线程编程-(1)-线程安全和锁Synchronized概念Java多线程编程-(2)-可重入锁以及Synchronized的其他基本特性Java多线程编程-(3)-线程本地ThreadLocal的介绍与使用Java多线程编程-(4)-线程间通信机制的介绍与使用Java多线程编程-(5)-使用Lock对象实现同步以及线程间通信Java多线程编程-(6)-两种常用的线程计数器Count

徐刘根的博客 2万+

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

Java多线程之ThreadLocal原理源码分析

什么是ThreadLocal? ThreadLocal 是线程的局部变量, 是每一个线程所单独持有的,其他线程不能对其进行访问, 通常是类中的 private static 字段,是对该字段初始值的一个拷贝,它们希望将状态与某一个线程(例如,用户 ID 或事务 ID)相关联 我们知道有时候一个对象的变量会被多个线程所访问,这时就会有线程安全问题,当然我们可以使用synchorinized 关键...

zp的博客 347

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

Java多线程编程-(9)-ThreadLocal造成OOM内存溢出案例演示与原理分析

前几篇: Java多线程编程-(1)-线程安全和锁Synchronized概念 Java多线程编程-(2)-可重入锁以及Synchronized的其他基本特性 Java多线程编程-(3)-线程本地ThreadLocal的介绍与使用 Java多线程编程-(4)-线程间通信机制的介绍与使用 Java多线程编程-(5)-使用Lock对象实现同步以及线程间通信 Java多线程编程-(6)-两种...

徐刘根的博客 2万+

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

【Java多线程】ThreadLocal原理+源码分析+使用场景和好处

ThreadLocal ​ ThreadLocal,根据名字知道肯定是跟线程有关,而且每个线程之间的同一个class的实例对象是固定的且独立,因为是local嘛。 ​ ThreadLocal是对于每个线程拿到的对象实例都是不同的对象实例,使得各个对象隔离、独立。 ThreadLocal底层原理 我们来看看Thread、ThreadLocal和ThreadLocalMap的关系 每个线程都有自己的一个ThreadLocalMap,因为一个线程可能有多个ThreadLocal 每个ThreadLoca

Miiiiiiiiiii的博客 284

[Java多线程]-ThreadLocal源码及原理的深入分析

ThreadLocal<T>类:以空间换时间提供一种多线程更快捷访问变量的方式。这种方式不存在竞争,所以也不存在并发的安全性问题。 //---------------------------------------------------update:2017/3/21-----------------------------------------------------...

weixin_30808693的博客 98

Java多线程----很多人问的ThreadLocal实现原理和过程(源码分析)

Java线程—ThreadLocal 辨析ThreadLocal 用法(如有错误,欢迎指正!)与Synchonized 的比较ThreadLocal 实现ThreadLocal 解析get()---返回当前线程所对应的线程局部变量---get( )---getMap()---threadLocals---ThreadLocalMapset()---设置当前线程的线程局部变量的值---set()---getMap()---createMap()---ThreadLocalMap()---threadLocal

何义竏 438

Java多线程编程-(11)-面试常客ThreadLocal出现OOM内存溢出的场景和原理分析

Java多线程编程-(1)-线程安全和锁Synchronized概念 Java多线程编程-(2)-可重入锁以及Synchronized的其他基本特性 Java多线程编程-(3)-从一个错误的双重校验锁代码谈一下volatile关键字 Java多线程编程-(4)-线程本地ThreadLocal的介绍与使用 Java多线程编程-(5)-线程间通信机制的介绍与使用 Java

Java后端技术 6909

Java(面试必备):面试中的 ThreadLocal 原理和使用场景

面试中的 ThreadLocal 原理和使用场景 前言 今天博主将为大家分享Java(面试必备):面试中的 ThreadLocal 原理和使用场景,不喜勿喷,如有异议欢迎讨论! 相信大家在面试中经常被问过 ThreadLocal 的原理和用法,虽然一直知道这个东西的存在但是一直没有好好的研究一下原理,没有自己的知识体系。今天安利一波有待提高 ThreadLocal 是什么 ThreadLoca...

Mr_chen的博客 1万+

Java多线程9:ThreadLocal原理和使用场景

前言:面试官经常会问到 ThreadLocal 是什么?他其实想考察候选人对ThreadLocal的定义、原理和应用场景的了解程度。 一、ThreadLocal定义 ThreadLocal,线程本地变量,顾名思义,它是每个线程私有的本地变量。通俗点讲,当你创建了一个ThreadLocal变量,每个线程在访问该变量时,都会拷贝一个副本至本地内存,所以多线程下操作ThreadLocal变量时,其实各自都是在操作自己拷贝的副本,互不影响,这样自然而然就避免了线程安全问题。 ThreadLocal有点类似

何哥的博客 4499

Java多线程中ThreadLocal解析

       Java多线程中,常常会用到这样一个类,ThreadLocal。这个类是用来干什么的呢,我们先来看一段代码。private static final ThreadLocal threadSession = new ThreadLocal(); public static Session getSession() throws InfrastructureException { ...

此心光明,亦复何言~ 364

ThreadLocal介绍

ThreadLocal可以使得线程之间相互隔离,也就是说线程A更改了ThreadLocal变量的值,线程B却不会知道,ThreadLocal不仅可以降低代码的耦合度,而且不会阻塞线程。 1.代码示例 public static void main(String[] args) { ThreadLocal<Persion> tl = new ThreadLocal<>(); new Thread(() -> { try { Thread

未来已来 212
上一篇: Synchronized 底层原理总结
下一篇: 多线程环境下,HashMap 为什么会出现死循环?
java111112313213
博客等级 码龄5年 15粉丝 73原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值