当前位置: 首页> 娱乐> 明星 > 苏州建站模板展示_微信公众平台官方网_百度信息流代理_磁力屋 最好用

苏州建站模板展示_微信公众平台官方网_百度信息流代理_磁力屋 最好用

时间:2025/7/9 23:02:46来源:https://blog.csdn.net/weixin_50087960/article/details/144735419 浏览次数:0次
苏州建站模板展示_微信公众平台官方网_百度信息流代理_磁力屋 最好用

ThreadLocal 详解

1: ThreadLocal简介

ThreadLocal是一个将在多线程中为每个线程创建单独的变量副本的类。当使用 ThreadLocal来维护变量时,ThreadLocal 会为每个线程创建单独的变量副本,避免因多线程操作共享变量而导致的数据不一致情况。

2:ThreadLocal的简单使用

public class ThreadRunnable implements Runnable {private ThreadLocal<String> threadLocal = new ThreadLocal<>();@Overridepublic void run() {// 设置ThreadLocal的值threadLocal.set("hello world");// 获取ThreadLocal的值String value = threadLocal.get();System.out.println(value);}public static void main(String[] args) {ThreadRunnable threadRunnable = new ThreadRunnable();Thread thread = new Thread(threadRunnable);thread.start();}
}

3: ThreadLocal 源码

get() 方法

public T get() {//获取当前线程Thread t = Thread.currentThread();//从当前线程中获取threadLocals变量的信息ThreadLocalMap map = getMap(t);//如果当前线程中存在信息if (map != null) {//通过当前线程的hash值获取ThreadLocalMap.Entry的信息ThreadLocalMap.Entry e = map.getEntry(this);if (e != null) {//如果不为空,获取对应的值并返回该对象信息T result = (T)e.value;return result;}}//如果当前线程的threadLocals为null的时候,则进行初始化return setInitialValue();}

当前线程初始化方法

   private T setInitialValue() {//首先初始化一个null值T value = initialValue();Thread t = Thread.currentThread();//获取当前线程threadLocals的变量值ThreadLocalMap map = getMap(t);if (map != null) {//如果不为空,则对当前线程的数据进行清空map.set(this, value);} else {//初始化ThreadLocalMap 给当前线程threadLocals变量赋值createMap(t, value);}//返回初始化的null值return value;}

set()方法

   public void set(T value) {//获取当前线程Thread t = Thread.currentThread();//获取当前线程threadLocals的变量值ThreadLocalMap map = getMap(t);if (map != null)//如果已存在,则将值加入到ThreadLocalMap中map.set(this, value);else//初始化ThreadLocalMap 给当前线程threadLocals变量赋值createMap(t, value);}

remove()方法

public void remove() {//通过当前线程的hash值获取ThreadLocalMapThreadLocalMap m = getMap(Thread.currentThread());if (m != null)//ThreadLocalMap删除当前线程信息m.remove(this);}

总结: 通过源码可知,ThreadLocal类封装了线程中threadLocals变量的增删操作。其中最核心就是ThreadLocalMap结构。下面我看下ThreadLocalMap 的结构

4: ThreadLocalMap

ThreadLocalMap源码

 static class ThreadLocalMap {static class Entry extends WeakReference<ThreadLocal<?>> {/** The value associated with this ThreadLocal. */Object value;Entry(ThreadLocal<?> k, Object v) {//Entry继承WeakReference,k是调用WeakReference构造方法。super(k);value = v;}}
}        

方法注释上来看 :

ThreadLocalMap 是一个自定义的哈希映射,仅适用于维护线程本地值。不会在 ThreadLocal 类之外导出任何操作。为了帮助处理非常大且生存期较长的使用,哈希表条目对键使用 WeakReferences。当空间不足的时候,会删除过时信息。

总结:

从ThreadLocalMap源码和官方注释中可以知道,当空间不足的时候,WeakReferences的对象信息会被垃圾回收。这个时候value的值就无法被删除,导致内存泄露问题。由于篇幅有限,后续会继续分享内存泄露相关的问题。

5: 应用场景

ThreadLocal 通常被推荐用于以下几种情况

  • 当需要在多线程的环境下保存线程安全的状态信息时候
  • 当你需要在同一个线程的多个操作中传递数据,而不想通过参数的方式来传递

最为常见的场景

5.1 用户身份信息传递

public class UserContextHolder {// 使用 ThreadLocal 保存用户信息private static final ThreadLocal<User> userHolder = new ThreadLocal<>();// 将用户信息与当前线程关联public static void setUser(User user) {userHolder.set(user);}// 获取与当前线程关联的用户信息public static User getUser() {return userHolder.get();}// 移除与当前线程关联的用户信息public static void remove() {userHolder.remove();}
}

5.2 数据库连接管理

例如Mybatis中SqlSessionManager类,用于存储数据库交互信息

public class SqlSessionManager implements SqlSessionFactory, SqlSession {private final ThreadLocal<SqlSession> localSqlSession = new ThreadLocal<>();public void startManagedSession() {this.localSqlSession.set(openSession());} 		@Overridepublic void commit() {final SqlSession sqlSession = localSqlSession.get();if (sqlSession == null) {throw new SqlSessionException("Error:  Cannot commit.  No managed session is started.");}sqlSession.commit();}
}
关键字:苏州建站模板展示_微信公众平台官方网_百度信息流代理_磁力屋 最好用

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: