iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >Java之ThreadLocal使用常见和方式有哪些
  • 603
分享到

Java之ThreadLocal使用常见和方式有哪些

2023-06-20 20:06:00 603人浏览 薄情痞子
摘要

这篇文章主要介绍了Java之ThreadLocal使用常见和方式有哪些,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。1 两大使用场景-ThreadLocal的用途典型场景1:

这篇文章主要介绍了Java之ThreadLocal使用常见和方式有哪些,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

1 两大使用场景-ThreadLocal的用途

  • 典型场景1:每个线程需要一个独享的对象(通常是工具类,典型需要使用的类有SimpleDateFORMat和Random)

  • 典型场景2:每个线程内需要保存全局变量(例如在拦截器中获取用户信息),可以让不同方法直接使用,避免参数传递的麻烦。

2 典型场景1:每个线程需要一个独享的对象

每个Thread内有自己的实例副本,不共享;

举例:SimpleDateFormat。(当多个线程共用这样一个SimpleDateFormat,但是这个类是不安全的)

  • 2个线程分别用自己的SimpleDateFormat,这没问题;

  • 后来延伸出10个,那就有10个线程和10个SimpleDateFormat,这虽然写法不优雅,但勉强可以接受

  • 但是当需求变成了1000,那么必然要用线程池,消耗内存太多;

  • 但是每一个SimpleDateFormat我们都需要创建一遍,那么太耗费new对象了,改成static共用的,所有线程都共用一个simpleDateFormat对象,但这是线程不安全的,容易出现时间一致的情况,在调用的时候,可加来解决,但还是不优雅;

  • 用ThreadLocal来解决该问题,给每个线程分配一个simpledateformat,可这个threadlocal是安全的;

package threadlocal;import java.text.SimpleDateFormat;import java.util.Date;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class ThreadLocalNormalUsage05 {    public static ExecutorService threadPool = Executors.newFixedThreadPool(10);    public static void main(String[] args) throws InterruptedException {        for (int i = 0; i < 1000; i++) {            int finalI = i;            threadPool.submit(new Runnable() {                @Override                public void run() {                    String date = new ThreadLocalNormalUsage05().date(finalI);                    System.out.println(date);                }            });        }        threadPool.shutdown();    }    public String date(int seconds) {        //参数的单位是毫秒,从1970.1.1 00:00:00 GMT计时        Date date = new Date(1000 * seconds);//        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");        SimpleDateFormat dateFormat = ThreadSafeFormatter.dateFormatThreadLocal2.get();        return dateFormat.format(date);    }}class ThreadSafeFormatter {    public static ThreadLocal<SimpleDateFormat> dateFormatThreadLocal = new ThreadLocal<SimpleDateFormat>() {        @Override        protected SimpleDateFormat initialValue() {            return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");        }    };    public static ThreadLocal<SimpleDateFormat> dateFormatThreadLocal2 = ThreadLocal            .withInitial(() -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));}

3 典型场景2:当前用户信息需要被线程内所有方法共享

  • 一个比较繁琐的解决方案是把user作为参数层层传递,从service-1()传到service-2(),以此类推,但是这样做会导致代码冗余且不易维护。

  • 进阶点就是userMap来保存,但是当多线程同时工作时,需要保证线程安全,需要用synchronized,或者concurrentHashMap,但无论用什么,都会对性能有所影响

每个线程内需要保存全局变量,可以让不同方法直接使用,避免参数传递的麻烦

  • 用ThreadLocal保存一些业务内存(用户权限信息,从用户系统获取到的用户名、userId等)

  • 这些信息在同一个线程内相同,但是不同的线程使用的业务内容是不相同的

  • 在线程生命周期内,都通过这个静态ThreadLocal实例的get()方法取得自己set过的那个对象,避免了将这个对象作为参数传递的麻烦

package threadlocal;public class ThreadLocalNormalUsage06 {    public static void main(String[] args) {        new Service1().process("");    }}class Service1 {    public void process(String name) {        User user = new User("超哥");        UserContextHolder.holder.set(user);        new Service2().process();    }}class Service2 {    public void process() {        User user = UserContextHolder.holder.get();        ThreadSafeFormatter.dateFormatThreadLocal.get();        System.out.println("Service2拿到用户名:" + user.name);        new Service3().process();    }}class Service3 {    public void process() {        User user = UserContextHolder.holder.get();        System.out.println("Service3拿到用户名:" + user.name);        UserContextHolder.holder.remove();    }}class UserContextHolder {    public static ThreadLocal<User> holder = new ThreadLocal<>();}class User {    String name;    public User(String name) {        this.name = name;    }}

注意点:

  • 强调的是同一个请求内(同一个线程内)不同方法见的共享;

  • 不需重写initialValue()方法,但是必须手动调用set()方法

4 ThreadLocal方法使用总结

场景一:initialValue

在ThreadLocal第一次get的时候把对象给初始化出来,对象的初始化时机可以由我们控制。

场景二:set

如果需要保存到ThreadLocal里面的对象的生成时机不由我们随意控制。例如拦截器生成的用户信息,用ThreadLocal.set直接放到ThreadLocal当中。

5 ThreadLocal原理

理清Thread,ThreadLocalMap以及ThreadLocal

Java之ThreadLocal使用常见和方式有哪些

主要方法介绍

  • T initialValue(): 初始化

  • void set(T t): 为这个线程设置一新值

  • T get(): 得到这个线程对应的value。如果是首次调用get()。则会调用initialize来得到这个值

  • void remove(): 删除这个线程得到的值

ThreadLocalMap发生冲突之后,会用线性探测法。

6 ThreadLocal使用问题内存泄露

什么是内存泄露:某个对象不再有用,但是占用的内存却不能被回收。

Value的泄露

  • 在ThreadLocalMap中的每个Entry都是一个对key的弱引用,同时,每个Entry都包含了一个对value的强引用。

  • 正常情况 ,当线程终止,保存在ThreadLocal里的value会被垃圾回收,因为没有任何强引用了。

  • 但是,如果线程不终止(比如线程池需要保持很久),那么key对应的value就不能被回收。Thread->ThreadLocalMap->Entry(key为Null)->Value

  • 因为value和Thread之间还存在这个强引用链路,所以导致value无法回收,就可能出现OOM;jdk已经考虑到这个问题,所以在set,remove,rehash方法中会扫描key为null,会把value也设置为null,这样value对象就可以被回收了。

  • 但是如果一个ThreadLocal不被使用,那么实际上set,remove,rehash方法也不会被调用,如果同时线程又不停止,那么调用链就一直存在,那么就导致了value的内存泄露。

如何避免内存泄露呢?

  • 调用remove方法,就会删除对应的Entry对象,可以避免内存泄露,所以使用完ThreadLocal之后,应该调用remove方法。

7 实际应用场景-在spring中的实例分析

  • DateTimeContextHolder:用到了ThreadLocal

  • RequestContextHolder:用到了ThreadLocal

感谢你能够认真阅读完这篇文章,希望小编分享的“Java之ThreadLocal使用常见和方式有哪些”这篇文章对大家有帮助,同时也希望大家多多支持编程网,关注编程网精选频道,更多相关知识等着你来学习!

--结束END--

本文标题: Java之ThreadLocal使用常见和方式有哪些

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

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

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

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

下载Word文档
猜你喜欢
  • Java之ThreadLocal使用常见和方式有哪些
    这篇文章主要介绍了Java之ThreadLocal使用常见和方式有哪些,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。1 两大使用场景-ThreadLocal的用途典型场景1:...
    99+
    2023-06-20
  • Java之ThreadLocal使用常见和方式案例讲解
    目录1 两大使用场景-ThreadLocal的用途2 典型场景1:每个线程需要一个独享的对象3 典型场景2:当前用户信息需要被线程内所有方法共享4 ThreadLocal方法使用总结...
    99+
    2022-11-12
  • Redis常见使用方式有哪些
    这篇“Redis常见使用方式有哪些”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Redis常见使用方式有哪些”文章吧。一、常...
    99+
    2023-06-05
  • Java中enum常见的使用方法有哪些
    这篇文章主要介绍了Java中enum常见的使用方法有哪些,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。Java的特点有哪些Java的特点有哪些1.Java语言作为静态面向对象...
    99+
    2023-06-14
  • Java常见设计模式有哪些
    这篇文章主要介绍Java常见设计模式有哪些,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一、设计模式总述:1、什么是设计模式:设计模式是一套经过反复使用的代码设计经验,目的是为了重用代码、让代码更容易被他人理解、保证...
    99+
    2023-06-29
  • Vue2常见开局方式有哪些
    这篇文章给大家分享的是有关Vue2常见开局方式有哪些的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。在SF问题中看到了一个关于vue-cli中的template问题,问题是这样的:...
    99+
    2022-10-19
  • 有哪些常见换ip的方式
    这篇文章主要介绍“有哪些常见换ip的方式”,在日常操作中,相信很多人在有哪些常见换ip的方式问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”有哪些常见换ip的方式”的疑惑有所帮助!接下来,请跟着小编一起来学习吧...
    99+
    2023-06-20
  • java中ThreadLocal的使用场景有哪些
    今天就跟大家聊聊有关java中ThreadLocal的使用场景有哪些,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。常用的java框架有哪些1.SpringMVC,Spring Web...
    99+
    2023-06-14
  • Java中StringBuilder()常见方法有哪些
    在Java中,StringBuilder类提供了多个常见的方法用于字符串的操作,以下是一些常用的方法:1. append(Strin...
    99+
    2023-09-13
    Java
  • Java中字符串常见的拼接方式有哪些
    这篇“Java中字符串常见的拼接方式有哪些”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Java中字符串常见的拼接方式有哪些...
    99+
    2023-07-05
  • 常见的HashMap迭代方式有哪些
    这篇文章主要介绍了常见的HashMap迭代方式有哪些的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇常见的HashMap迭代方式有哪些文章都会有所收获,下面我们一起来看看吧。一、 HashMap介绍HashMap...
    99+
    2023-06-27
  • 常见的DDOS攻击方式有哪些
    常见的DDOS攻击方式有:1、SYN/ACK Flood攻击,通过向受害主机发送大量伪造源IP和源端口的SYN或ACK包,导致主机缓存资源被耗尽或忙于发送回应包而造成拒绝服务;2、TCP全连接攻击,通过许多僵尸主机不断与受害服务器建立大量的...
    99+
    2022-10-09
  • java常见的加密方法有哪些
    Java常见的加密方法有以下几种:1. 对称加密:对称加密算法使用相同的密钥对数据进行加密和解密,常见的对称加密算法有DES、3DE...
    99+
    2023-09-06
    java
  • 负载均衡常见的方式有哪些
    负载均衡常见的方式有以下几种:1. 基于网络层的负载均衡:通过路由器或交换机等网络设备,根据目标IP地址或端口号来分发请求。常见的网...
    99+
    2023-09-01
    负载均衡
  • 常见数据库连接方式有哪些
    这篇文章给大家分享的是有关常见数据库连接方式有哪些的内容。小编觉得挺实用的,因此分享给大家做个参考。一起跟随小编过来看看吧。1.Access数据库的DSN-less连接方法:set adocon=Serve...
    99+
    2022-10-18
  • 有哪些常见的网络推广方式
    本篇文章给大家分享的是有关有哪些常见的网络推广方式,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。网络推广(web promotion)是以企业产品或服务为核心内容,建立网站、A...
    99+
    2023-06-14
  • appium中常见的点击方式有哪些
    小编给大家分享一下appium中常见的点击方式有哪些,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!首先从appium库里面导入webdriver,然后webdri...
    99+
    2023-06-29
  • Python中有哪些常见的加密方式
    Python中有哪些常见的加密方式,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。前言我们所说的加密方式,都是对二进制编码的格式进行加密的,对应到Python中,则是我们的B...
    99+
    2023-06-02
  • 常用的java重构方式有哪些
    常用的Java重构方式包括:1. 提取方法(Extract Method):将一段代码逻辑提取为一个独立的方法,提高代码的可读性和可...
    99+
    2023-10-19
    java
  • php常见设计模式和用途有哪些
    PHP常见的设计模式有以下几种:1. 工厂模式(Factory Pattern):用于创建对象,隐藏对象创建的具体细节,客户端只需要...
    99+
    2023-09-29
    php
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作