千家信息网

ThreadLocal使用方法是什么

发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,这篇"ThreadLocal使用方法是什么"文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这
千家信息网最后更新 2026年11月03日ThreadLocal使用方法是什么

这篇"ThreadLocal使用方法是什么"文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇"ThreadLocal使用方法是什么"文章吧。

一、常见场景

1、ThreadLocal作为线程上下文副本,那么一种最常见的使用方式就是用来方法隐式传参,通过提供的set()和get()两个public方法来实现在不同的方法中的参数传递。对于编程规范来说,方法定义的时候是对参数个数是有限制的,甚至在一些大厂,对方法参数个数是有明确规定的。

2、线程安全,每个线程维持自己的变量,以免紊乱,像常用的数据库的连接池的线程安全实现就使用了ThreadLocal。

二、进阶使用

以参数传递为例子,如何更好地使用ThreadLocal来实现在同一线程栈中不同方法中的参数传递。在参数传递的时候,那么都会有参数名,参数值,而ThreadLocal提供的get()和set()方法,不能直接满足设置参数名和参数值。这种情况下就需要对ThreadLocal进一次封装,如下代码,维护一个map对象,然后提供setValue(key, value)和getValue(key, value)方法,就可以很方便地实现了参数的设置和获取;在需要的地方对参数进行清理,使用remove(key)或者clear()即可实现。

import java.util.HashMap;import java.util.Map; public class ThreadLocalManger extends ThreadLocal {     private static ThreadLocalManger> MANGER = new ThreadLocalManger<>();     private static HashMap MANGER_MAP = new HashMap<>();     public static void setValue(String key, Object value) {        Map context = MANGER.get();        if(context == null) {            synchronized (MANGER_MAP) {                if(context == null) {                    context = new HashMap<>();                    MANGER.set(context);                }            }        }        context.put(key, value);    }     public static Object getValue(String key) {        Map context = MANGER.get();        if(context != null) {            return context.get(key);        }        return null;    }     public static void remove(String key) {        Map context = MANGER.get();        if(context != null) {            context.remove(key);        }    }     public static void clear() {        Map context = MANGER.get();        if(context != null) {            context.clear();        }    }}

三、使用漏洞

继续以参数传递为例子,来看看ThreadLocal使用过程中存在的问题和后果。在实际业务的功能开发中,为了提升效率,大部分情况下都会使用线程池来实现,比如数据库的连接池、RPC请求连接池、MQ消息处理池、后台批量job池等等;同时也可能会使用一个伴随整个应用生命周期的线程(守护线程)来实现的一些功能,比如说心跳、监控等等。使用线程池,那么在实际生产业务中并发肯定不低,池中线程就会一直复用;守护线程一旦创建,那么就会活到应用停机。所以在这些情况下,线程的生命周期很长,在使用ThreadLocal的时候,一定要进行清理,不然就会有内存溢出的情况发生。通过以下案例来模拟内存溢出的情况。

通过一个死循环来模拟高并发场景。创建一个10个核心线程数,10个最大线程数数,60秒空闲时间的、线程名以ThreadLocal-demo-开头的线程池,在该场景下,将有10个线程来运行,运行内容很简单:生成一个UUID,并将其作为参数key,然后设置到线程副本中。

import org.springframework.scheduling.concurrent.CustomizableThreadFactory;import org.springframework.stereotype.Service; import java.util.UUID;import java.util.concurrent.*; @Servicepublic class ThreadLocalService {     ThreadFactory springThreadFactory = new CustomizableThreadFactory("TheadLocal-demo-");     ExecutorService executorService = new ThreadPoolExecutor(10, 10, 60,            TimeUnit.SECONDS, new LinkedBlockingQueue<>(), springThreadFactory);     ExecutorService service = new ThreadPoolExecutor(10, 10, 60,            TimeUnit.SECONDS, new LinkedBlockingQueue<>());     public Object setValue() {        for(; ;) {            try {                Runnable runnable = new Runnable() {                    @Override                    public void run() {                        String id = UUID.randomUUID().toString();                        // add                        ThreadLocalManger.setValue(id, "this is a value");                        //do something here                        ThreadLocalManger.getValue(id);                        // clear()                        //ThreadLocalManger.clear();                    }                };                executorService.submit(runnable);            } catch (Exception e) {                e.printStackTrace();                break;            }        }        return "success";    } }

以上代码中已把clear()方法注释掉,不做清理,触发程序,稍微将jvm设置低一些,跑不久就会报如下OOM。

java.lang.OutOfMemoryError: GC overhead limit exceededException in thread "TheadLocal-demo-9" Exception in thread "TheadLocal-demo-8" Exception in thread "TheadLocal-demo-6" Exception in thread "TheadLocal-demo-10" Exception in thread "TheadLocal-demo-7" java.lang.OutOfMemoryError: GC overhead limit exceededException in thread "TheadLocal-demo-5" java.lang.OutOfMemoryError: GC overhead limit exceededjava.lang.OutOfMemoryError: GC overhead limit exceededjava.lang.OutOfMemoryError: GC overhead limit exceeded    at com.intellij.rt.debugger.agent.CaptureStorage.insertEnter(CaptureStorage.java:57)    at java.util.concurrent.FutureTask.run(FutureTask.java)    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)    at java.lang.Thread.run(Thread.java:748)java.lang.OutOfMemoryError: GC overhead limit exceededjava.lang.OutOfMemoryError: GC overhead limit exceeded

就会发生严重的内存溢出,通过如下debug截图可知,设置进去的UUID堆积在内存中,逐步变多,最终撑爆内存。

在实际的业务场景中,需要传递的可能有订单号,交易号,流水号等等,这些变量往往是唯一不重复的、符合案例中的UUID情况,在不清理的情况下就会造成应用OOM,进而不可用;在分布式系统中,还能导致上下游系统不可用,进而导致整个分布式进去的不可用;如果这些信息往往还可能用在网络传输中,大消息占有网络带宽,严重甚至导致网络瘫痪。所以一个小小的细节就会置整个集群于危险之中,那么如何合理化解呢。

四、终阶使用

以上问题在于忘记清理,那么如何让清理无感知,即不需要清理也没有问题。根因在于线程跑完一次之后,没有进行清理,所以可提供一个基类线程,在线程执行最后对清理进行封装。如下代码。提供一个BaseRunnable抽象基类,该类主要如下特点。

1、该类继承Runnable。

2、实现setArg(key, value)和getArg(key)两个方法。

2、在重写的run方式中分为两步,第一步,调用抽象方法task;第二步,清理线程副本。

有了以上3个特点,继承了BaseRunnable的线程类,只需要在实现task方法,在task方法中实现业务逻辑,参数传递和获取通过setArg(key, value)和getArg(key)两个方法即可实现,无需再显示清理。

public abstract class BaseRunnable implements Runnable {     @Override    public void run() {        try {            task();        } finally {            ThreadLocalManger.clear();        }    }     public void setArg(String key, String value) {        ThreadLocalManger.setValue(key, value);    }     public Object getArg(String key) {        return ThreadLocalManger.getValue(key);    }     public abstract void task();}

以上就是关于"ThreadLocal使用方法是什么"这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注行业资讯频道。

线程 方法 参数 情况 内容 内存 业务 使用方法 两个 代码 副本 场景 实际 时候 网络 问题 应用 不同 安全 上下 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 哈尔滨大商圈互联网科技有限公司 互联网科技深圳 互联网为科技 美国互联网科技巨头监管 青岛互联网科技公司 远信互联网科技 互联网科技缩写 猫创互联网科技 互联网科技视频素材 青岛中康互联网医疗科技有限公司 福州新华互联网科技学校 知乎 南山科技园互联网公司有哪些 晓花互联网科技有限公司网址 玉溪新华互联网科技好不好 科技赋能视角下互联网保险发展 工业互联网山东科技大学 本届互联网大会上的黑科技 郑州欣桑互联网科技有限公司 互联网时代科技型公司的机会 知域互联网科技有限公司官网 保险科技 互联网保险 齐家互联网科技 奇酷互联网络科技公司 互联网养老 桔豆科技 富国互联网科技创新基金 黑科技闪耀互联网之光 宜昌元轩互联网科技有限公司 内蒙古九一互联网科技 深圳互联网科技的发展 如何强化互联网金融科技
0