iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >Java中ThreadLocal类怎么使用
  • 707
分享到

Java中ThreadLocal类怎么使用

2023-06-29 21:06:13 707人浏览 独家记忆
摘要

这篇文章主要介绍“Java中ThreadLocal类怎么使用”,在日常操作中,相信很多人在Java中ThreadLocal类怎么使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java中ThreadLoca

这篇文章主要介绍“Java中ThreadLocal类怎么使用”,在日常操作中,相信很多人在Java中ThreadLocal类怎么使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java中ThreadLocal类怎么使用”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

    Threadlocal有什么用:

    简单的说就是,一个ThreadLocal在一个线程中是共享的,在不同线程之间又是隔离的(每个线程都只能看到自己线程的值)。如下图:

    Java中ThreadLocal类怎么使用

    ThreadLocal使用实例

    api介绍

    在使用Threadlocal之前我们先看以下它的API:

    Java中ThreadLocal类怎么使用

    ThreadLocal类的API非常的简单,在这里比较重要的就是get()、set()、remove(),set用于赋值操作,get用于获取变量的值,remove就是删除当前变量的值.需要注意的是initialValue方法会在第一次调用时被触发,用于初始化当前变量值,默认情况下initialValue返回的是null。

    ThreadLocal的使用

    说完了ThreadLocal类的API了,那我们就来动手实践一下了,来理解前面的那句话:一个ThreadLocal在一个线程中是共享的,在不同线程之间又是隔离的(每个线程都只能看到自己线程的值)

    public class ThreadLocalTest {    private static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>() {// 重写这个方法,可以修改“线程变量”的初始值,默认是null        @Override        protected Integer initialValue() {            return 0;        }    };    public static void main(String[] args) throws InterruptedException {        //一号线程        new Thread(new Runnable() {            @Override            public void run() {                System.out.println("一号线程set前:" + threadLocal.get());                threadLocal.set(1);                System.out.println("一号线程set后:" + threadLocal.get());            }        }).start();        //二号线程        new Thread(new Runnable() {            @Override            public void run() {                System.out.println("二号线程set前:" + threadLocal.get());                threadLocal.set(2);                System.out.println("二号线程set后:" + threadLocal.get());            }        }).start();        //主线程睡1s        Thread.sleep(1000);        //主线程        System.out.println("主线程的threadlocal值:" + threadLocal.get());    }}

    稍微解释一下上面的代码:

    每一个ThreadLocal实例就类似于一个变量名,不同的ThreadLocal实例就是不同的变量名,它们内部会存有一个值(暂时这么理解)在后面的描述中所说的“ThreadLocal变量或者是线程变量”代表的就是ThreadLocal类的实例。

    在类中创建了一个静态的 “ThreadLocal变量”,在主线程中创建两个线程,在这两个线程中分别设置ThreadLocal变量为1和2。然后等待一号和二号线程执行完毕后,在主线程中查看ThreadLocal变量的值。

    程序结果及分析⌛

    Java中ThreadLocal类怎么使用

    程序结果重点看的是主线程输出的是0,如果是一个普通变量,在一号线程和二号线程中将普通变量设置为1和2,那么在一二号线程执行完毕后在打印这个变量,输出的值肯定是1或者2(到底输出哪一个由操作系统的线程调度逻辑有关)。但使用ThreadLocal变量通过两个线程赋值后,在主线程程中输出的却是初始值0。在这也就是为什么“一个ThreadLocal在一个线程中是共享的,在不同线程之间又是隔离的”,每个线程都只能看到自己线程的值,这也就是 ThreadLocal的核心作用:实现线程范围的局部变量。

    Threadlocal 的源码分析

    原理

    每个Thread对象都有一个ThreadLocalMap,当创建一个ThreadLocal的时候,就会将该ThreadLocal对象添加到该Map中,其中键就是ThreadLocal,值可以是任意类型。 这句话刚看可能不是很懂,下面我们一起看完源码就明白了。

    前面我们的理解是所有的常量值或者是引用类型的引用都是保存在ThreadLocal实例中的,但实际上不是的,这种说法只是让我们更好的理解ThreadLocal变量这个概念。向ThreadLocal存入一个值,实际上是向当前线程对象中的ThreadLocalMap存入值,ThreadLocalMap我们可以简单的理解成一个Map,而向这个Map存值的key就是ThreadLocal实例本身。

    源码

    Java中ThreadLocal类怎么使用

    ????也就是说,想要存入的ThreadLocal中的数据实际上并没有存到ThreadLocal对象中去,而是以这个ThreadLocal实例作为key存到了当前线程中的一个Map中去了,获取ThreadLocal的值时同样也是这个道理。这也就是为什么ThreadLocal可以实现线程之间隔离的原因了。

    内部类ThreadLocalMap

    ThreadLocalMap是ThreadLocal的内部类,实现了一套自己的Map结构✨

    ThreadLocalMap属性:

    static class Entry extends WeakReference<ThreadLocal<?>> {            Object value;            Entry(ThreadLocal<?> k, Object v) {                super(k);                value = v;            }        }        //初始容量16        private static final int INITIAL_CAPACITY = 16;        //散列表        private Entry[] table;        //entry 有效数量         private int size = 0;        //负载因子        private int threshold;

    ThreadLocalMap设置ThreadLocal 变量

    private void set(ThreadLocal<?> key, Object value) {            Entry[] tab = table;            int len = tab.length;                        //与运算  & (len-1) 这就是为什么 要求数组len 要求2的n次幂             //因为len减一后最后一个bit是1 与运算计算出来的数值下标 能保证全覆盖             //否者数组有效位会减半             //如果是HashMap 计算完下标后 会增加链表 或红黑树的查找计算量             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;                }                //槽点被GC掉 重设状态                 if (k == null) {                    replaceStaleEntry(key, value, i);                    return;                }            }//槽点为空 设置value            tab[i] = new Entry(key, value);            //设置ThreadLocal数量            int sz = ++size;//没有可清理的槽点 并且数量大于负载因子 rehash            if (!cleanSomeSlots(i, sz) && sz >= threshold)                rehash();        }

    ThreadLocalMap属性介绍????:

    • 和普通Hashmap类似存储在一个数组内,但与hashmap使用的拉链法解决散列冲突不同的是 ThreadLocalMap使用开放地址法

    • 数组 初始容量16,负载因子2/3

    • node节点 的key封装了WeakReference 用于回收

    ThreadLocalMap存储位置

    储存在Thread中,有两个ThreadLocalMap变量

    Java中ThreadLocal类怎么使用

    threadLocals 在ThreadLocal对象方法set中去创建 也由ThreadLocal来维护

    public void set(T value) {        Thread t = Thread.currentThread();        ThreadLocalMap map = getMap(t);        if (map != null)            map.set(this, value);        else            createMap(t, value);    }    void createMap(Thread t, T firstValue) {        t.threadLocals = new ThreadLocalMap(this, firstValue);    }

    inheritableThreadLocals 和ThreadLocal类似 InheritableThreadLocal重写了createMap方法

    void createMap(Thread t, T firstValue) {        t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);    }

    inheritableThreadLocals 作用是将ThreadLocalMap传递给子线程

    Java中ThreadLocal类怎么使用

    init方法中 条件满足后直接为子线程创建ThreadLocalMap

    Java中ThreadLocal类怎么使用

    注意:

    • 仅在初始化子线程的时候会传递 中途改变副线程的inheritableThreadLocals 变量 不会将影响结果传递到子线程 。

    • 使用线程池要注意 线程不回收 尽量避免使用父线程的inheritableThreadLocals 导致错误

    Key的弱引用问题

    为什么要用弱引用,官方是这样回答的

    To help deal with very large and long-lived usages, the hash table entries use WeakReferences for keys.

    为了处理非常大和生命周期非常长的线程,哈希表使用弱引用作为 key。

    生命周期长的线程可以理解为:线程池的核心线程

    ThreadLocal在没有外部对象强引用时如Thread,发生GC时弱引用Key会被回收,而Value是强引用不会回收,如果创建ThreadLocal的线程一直持续运行如线程池中的线程,那么这个Entry对象中的value就有可能一直得不到回收,发生内存泄露。

    • key 使用强引用????: 引用的ThreadLocal的对象被回收了,但是ThreadLocalMap还持有ThreadLocal的强引用,如果没有手动删除,ThreadLocal不会被回收,导致Entry内存泄漏。

    • key 使用弱引用????: 引用的ThreadLocal的对象被回收了,由于ThreadLocalMap持有ThreadLocal的弱引用,即使没有手动删除,ThreadLocal也会被回收。value在下一次ThreadLocalMap调用set,get,remove的时候会被清除。

    Java8中已经做了一些优化如,在ThreadLocal的get()、set()、remove()方法调用的时候会清除掉线程ThreadLocalMap中所有Entry中Key为null的Value,并将整个Entry设置为null,利于下次内存回收。

    java中的四种引用

    • 强引用????: 如果一个对象具有强引用,它就不会被垃圾回收器回收。即使当前内存空间不足,JVM也不会回收它,而是抛出 OutOfMemoryError 错误,使程序异常终止。如果想中断强引用和某个对象之间的关联,可以显式地将引用赋值为null,这样一来的话,JVM在合适的时间就会回收该对象

    • 软引用????: 在使用软引用时,如果内存的空间足够,软引用就能继续被使用,而不会被垃圾回收器回收,只有在内存不足时,软引用才会被垃圾回收器回收。(软引用可用来实现内存敏感的高速缓存,比如网页缓存、图片缓存等。使用软引用能防止内存泄露,增强程序的健壮性)

    • 弱引用????: 具有弱引用的对象拥有的生命周期更短暂。因为当 JVM 进行垃圾回收,一旦发现弱引用对象,无论当前内存空间是否充足,都会将弱引用回收。不过由于垃圾回收器是一个优先级较低的线程,所以并不一定能迅速发现弱引用对象

    • 虚引用????: 虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。虚引用必须和引用队列(ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。(注意哦,其它引用是被JVM回收后才被传入ReferenceQueue中的。由于这个机制,所以虚引用大多被用于引用销毁前的处理工作。可以使用在对象销毁前的一些操作,比如说资源释放等。)

    通常ThreadLocalMap的生命周期跟Thread(注意线程池中的Thread)一样长,如果没有手动删除对应key(线程使用结束归还给线程池了,其中的KV不再被使用但又不会GC回收,可认为是内存泄漏),一定会导致内存泄漏,但是使用弱引用可以多一层保障:弱引用ThreadLocal会被GC回收,不会内存泄漏,对应的value在下一次ThreadLocalMap调用set,get,remove的时候会被清除,Java8已经做了上面的代码优化。

    到此,关于“Java中ThreadLocal类怎么使用”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

    --结束END--

    本文标题: Java中ThreadLocal类怎么使用

    本文链接: https://www.lsjlt.com/news/326555.html(转载时请注明来源链接)

    有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

    本篇文章演示代码以及资料文档资料下载

    下载Word文档到电脑,方便收藏和打印~

    下载Word文档
    猜你喜欢
    • Java中ThreadLocal类怎么使用
      这篇文章主要介绍“Java中ThreadLocal类怎么使用”,在日常操作中,相信很多人在Java中ThreadLocal类怎么使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java中ThreadLoca...
      99+
      2023-06-29
    • ThreadLocal怎么在Java中使用
      今天就跟大家聊聊有关ThreadLocal怎么在Java中使用 ,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。一.对ThreadLocal的理解ThreadLocal,很多地方叫做线...
      99+
      2023-05-31
      java threadlocal ava
    • Java ThreadLocal类如何使用
      今天小编给大家分享一下Java ThreadLocal类如何使用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。如图...
      99+
      2023-07-02
    • java中ThreadLocal怎么用
      这篇文章将为大家详细讲解有关java中ThreadLocal怎么用,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。package test;public class Threa...
      99+
      2023-06-02
    • Java中的ThreadLocal怎么用
      这篇文章给大家分享的是有关Java中的ThreadLocal怎么用的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。引言ThreadLocal的官方API解释为:“该类提供了线程局部 (thread-local) &...
      99+
      2023-06-17
    • 怎么在java中使用ThreadLocal隔离线程
      这期内容当中小编将会给大家带来有关怎么在java中使用ThreadLocal隔离线程,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。Java的特点有哪些Java的特点有哪些1.Java语言作为静态面向对象编...
      99+
      2023-06-14
    • Java超详细讲解ThreadLocal类的使用
      目录Threadlocal有什么用:ThreadLocal使用实例API介绍ThreadLocal的使用Threadlocal 的源码分析原理源码内部类ThreadLocalMapT...
      99+
      2024-04-02
    • C#线程绑定ThreadLocal类怎么使用
      本篇内容主要讲解“C#线程绑定ThreadLocal类怎么使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C#线程绑定ThreadLocal类怎么使用”吧!在.Net 4.0的Thread里,...
      99+
      2023-07-02
    • 快速了解Java中ThreadLocal类
      最近看Android FrameWork层代码,看到了ThreadLocal这个类,有点儿陌生,就翻了各种相关博客一一拜读;自己随后又研究了一遍源码,发现自己的理解较之前阅读的博文有不同之处,所以决定自己写篇文章说说自己的理解,希望可以起到...
      99+
      2023-05-30
      java threadlocal ava
    • ThreadLocal如何在Java中使用
      本篇文章给大家分享的是有关ThreadLocal如何在Java中使用,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。1. 应用场景ThreadLocal 的常见应用场景有两种:多...
      99+
      2023-06-15
    • Java中ThreadLocal的原理是什么及怎么使用
      这篇文章主要介绍“Java中ThreadLocal的原理是什么及怎么使用”,在日常操作中,相信很多人在Java中ThreadLocal的原理是什么及怎么使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Jav...
      99+
      2023-07-06
    • Java中ThreadLocal有什么用
      这篇文章将为大家详细讲解有关Java中ThreadLocal有什么用,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。一、ThreadLocal简介多线程访问同一个共享变量的时候容易出现并发问题,特别是多个线...
      99+
      2023-06-15
    • 详解Java中ThreadLocal类型及简单用法
      目录1 基本概念2 简单使用3 应用场景4 底层原理4.1 set(Object)4.2 get()4.3 remove()4.4 ThreadLocalMap5 内存泄漏隐患和防止...
      99+
      2024-04-02
    • Java ThreadLocal的使用详解
      目录1. 应用场景1.1. 保障线程安全1.2. 显示传递参数2. 实现原理3. 注意事项ThreadLocal是线程私有的局部变量存储容器,可以理解成每个线程都有自己专属的存储容器...
      99+
      2024-04-02
    • java中ThreadLocal是什么
      ThreadLocal是JDK包提供的,称为线程本地变量,它将变量与线程绑定在一起,为每一个线程维护一个独立的变量副本,通过ThreadLocal可以将对象的可见范围限制在同一个线程内,从而避免了线程安全问题,对解决多线程程序的并发问题有一...
      99+
      2024-04-02
    • java中ThreadLocal的使用场景有哪些
      今天就跟大家聊聊有关java中ThreadLocal的使用场景有哪些,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。常用的java框架有哪些1.SpringMVC,Spring Web...
      99+
      2023-06-14
    • java中的ThreadLocal是什么
      这篇文章将为大家详细讲解有关java中的ThreadLocal是什么,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。简单介绍ThreadLocal一般称为线程本地变量,它是一种特殊的线程绑定机制,将变量与线...
      99+
      2023-06-19
    • java中ToStringBuilder类怎么使用
      ToStringBuilder类是apache.commons.lang包中的一个工具类,用于生成Java对象的toString()...
      99+
      2023-09-26
      java
    • java中page类怎么使用
      在Java中,Page类通常用于表示一个页面对象,可以用于分页查询或分页显示数据。下面是Page类的使用示例: 首先,你需要引入P...
      99+
      2024-02-29
      java
    • java中peekgraphic类怎么使用
      在Java中,没有名为`PeekGraphic`的标准类。我怀疑您可能指的是`java.awt.image.BufferedImag...
      99+
      2023-08-24
      java peekgraphic
    软考高级职称资格查询
    编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
    • 官方手机版

    • 微信公众号

    • 商务合作