项目开发最常见的模式就是拿着之前开发的工程到新的项目中修修改改,这种开发方式很快,主要功能该有的都有了,只要按照新的需求改改就能用,但是开发不可能一直都是同一拨人干这事,后来的人对整个项目也不会做到100%的了解,这样新近的人就会做一些重复的工作,一两次还没啥,但是多了之后后面开发的人就会被坑死。现在就是开发这种项目过程不多说了。
最近看之前的代码,程序中对内容库session连接处理的地方感觉很奇怪,大致处理方式如下:
//定义Session保存对象 private static Map<String, ThreadLocal<Session>> map = new HashMap<String, ThreadLocal<Session>>(); //获取session方法 public Session get(String targetDocName){ ThreadLocal<Session> threadLocalSession = map.get(map.get(targetDocName)); Session session = null; if(threadLocalSession == null){ threadLocalSession = new ThreadLocal<Session>(); map.put(targetDocName, threadLocalSession); } if(threadLocalSession.get() == null){ session = SessionUtil.getSession(targetDocName); threadLocalSession.set(session); } threadLocalSession.get(); return session.get(); }
因为需要获取多个连接库的session所以最外层用Map保存,但是里面使用ThreadLocal获取session的方式就很奇怪了,我们知道ThreadLocal定义的是线程变量,在一个线程中操作一个ThreadLocal变量是不会影响到这个变量在其他线程中的正常使用的。按照这个思路,程序中设置ThreadLocal变量的值,只会对当前线程有效,所以之后的线程通过threadLocalSession来获取session都会是空值,由于ThreadLocal这个对象的特殊性,造成了他的设计思路与实际的程序运行有出入,当然这里的实现不会影响程序的正确性,只是性能上的问题。
下面我们就来了解下ThreadLocal这个线程变量:
首先需要了解为什么ThreadLocal定义的是一个线程变量(解释下我对线程变量的理解,就是定义的这个变量作用域是当前线程,线程结束该变量随之释放。),我们打开jdk源码查看java.lang.Thread的实现,可以看到有如下实现:
/* ThreadLocal values pertaining to this thread. This map is maintained * by the ThreadLocal class. */ ThreadLocal.ThreadLocalMap threadLocals = null;
Thread的定义中就包含了一个ThreadLocal的属性,也就是说每一个线程执行的时候都有一个与之对应的ThreadLocal对象属性,看到这里我们大致可以明白为什么会说ThreadLocal是一个线程变量了,但是JDK中到底是如何做到将ThreadLocal设置为一个线程变量的呢,看这个属性的注释,这个变量由ThreadLocal维护,我们就知道答案在ThreadLocal中。
我们看下ThreadLocal中是如何实现get方法的:
/** * Returns the value in the current thread's copy of this * thread-local variable. If the variable has no value for the * current thread, it is first initialized to the value returned * by an invocation of the {@link #initialValue} method. * * @return the current thread's value of this thread-local */ public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) return (T)e.value; } return setInitialValue(); } /** * Get the map associated with a ThreadLocal. Overridden in * InheritableThreadLocal. * * @param t the current thread * @return the map */ ThreadLocalMap getMap(Thread t) { return t.threadLocals; }
get方法首先获取当前线程的threadLocals变量,这个变量在线程初始化时是空的, 所有在线程中第一次调用ThreadLocal对象的get方法会直接调用setInitialValue方法,setInitialValue方法实现如下:
/** * Variant of set() to establish initialValue. Used instead * of set() in case user has overridden the set() method. * * @return the initial value */ private T setInitialValue() { T value = initialValue(); Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); return value; }
这段代码就是将initialValue方法的返回值设置到当前线程,最后返回这个值,但是这个方法的返回值是null。回到我的项目中,由于ThreadLocal对象是直接创建的,所以在后面通过ThreadLocal的get方法都只会等到一个空值。
如果需要ThreadLocal对象有默认初始值,我们只需要重写这个方法就可以了。
//O为自定义类 ThreadLocal<O> threadLocal = new ThreadLocal<O>(){ public O initialValue(){ return new O(); } };
相关推荐
**线程局部变量(ThreadLocal)是Java编程中一个非常重要的工具类,它在多线程环境下提供了线程安全的数据存储。ThreadLocal并不是一个变量,而是一个类,它为每个线程都创建了一个独立的变量副本,使得每个线程都...
ThreadLocal通常被用来解决线程共享数据时可能出现的并发问题,避免了使用synchronized关键字进行同步控制的复杂性。 在Java中,ThreadLocal的工作原理是为每个线程创建一个单独的存储空间,每个线程可以独立地读写...
关键在于,一旦 `MyCounter` 被设置到 `ThreadLocal`,那么它将与当前线程绑定,除非显式地移除,否则即使 `LeakingServlet` 执行结束,`MyCounter` 也不会被清理。 `WebappClassLoader` 的生命周期与 web 应用紧密...
在服务器端,线程池的存在可能导致多个用户的请求被分配到同一个线程处理,因此,如果不注意清理,ThreadLocal变量可能会被不同用户访问到,造成数据泄露。 误区三:每个用户访问会有新的ThreadLocal 理论上来讲,...
这个功能是通过 Thread 类中的 threadLocals 属性来实现的,这个属性实际上是一个 Entry 数组,其中的每个 Entry 都是一个弱引用,易于在 GC 时被回收。 ThreadLocal 的工作机制是通过计算Hash值来确定在数组中的...
当线程结束时,与之关联的所有`ThreadLocal`变量也将自动被垃圾回收器回收。然而,如果线程持续运行但不再使用某些`ThreadLocal`变量,应显式调用`remove()`方法释放这些变量,避免内存泄漏。 #### 五、ThreadLocal...
理解ThreadLocal 理解ThreadLocal 理解ThreadLocal 理解ThreadLocal
在一些框架或库中,如Spring,ThreadLocal被用来存储线程相关的配置信息。 4. **局部状态:** 在多线程环境中,当每个线程需要有自己的状态(如计数器),ThreadLocal提供了一种优雅的解决方案。 尽管...
例如,如果一个`ThreadLocal`实例没有被正确地清理或释放,即使线程已经结束,其`ThreadLocalMap`也不会被垃圾回收。 为了解决这个问题,`ThreadLocal`提供了以下机制: 1. **弱引用**:由于`ThreadLocalMap`的键...
Java事务和ThreadLocal是两种在Java编程中至关重要的概念,它们分别用于处理多线程环境下的数据一致性问题和提供线程局部变量。 首先,我们来深入理解Java事务。在数据库操作中,事务是一系列操作的集合,这些操作...
- **弱引用**:ThreadLocalMap的键使用的是弱引用,当ThreadLocal变量不再被引用时,垃圾收集器可以回收ThreadLocal对象,但其在ThreadLocalMap中的引用不会立即被移除,以防止导致内存泄漏。 - **线程生命周期**:...
Entry继承自WeakReference<ThreadLocal>,这意味着ThreadLocal对象如果不再被引用,可以被垃圾收集器回收,避免内存泄漏。然而,这种设计也存在一个问题:如果ThreadLocal没有被外部引用,但其对应的Entry还在Map中...
因此,如果一个`ThreadLocal`变量在线程结束后仍然被其他线程引用,可能会导致内存泄漏。 **使用示例** 下面是一个简单的`ThreadLocal`使用示例: ```java public class ThreadLocalDemo { public static void ...
这些模式在多次使用后被广泛认可,成为了经验丰富的开发者之间的一种通用语言。本资料主要聚焦于两种设计模式以及Java中的ThreadLocal特性。 首先,我们来探讨单例模式。单例模式是一种确保一个类只有一个实例,并...
然而,如果线程仍然存活并且`ThreadLocalMap`中的值没有被其他引用保持,那么可能会出现所谓的"死键",这可能导致内存泄漏。因此,正确使用`ThreadLocal`的一个关键点是在线程结束或不再使用ThreadLocal时,及时调用...
学习ThreadLocal,了解其中的原理,以及学习其中的优点!避免坑点!!
但是,如果ThreadLocalMap中的值(通常是对象)仍然被其他强引用保持,那么即使ThreadLocal实例被回收,值仍然存在于ThreadLocalMap中,这可能导致内存泄漏。因此,务必在不再使用ThreadLocal变量时调用`remove()`。...