其实ThreadLocal并非是一个线程的本地实现版本,它并不是一个Thread,而是threadlocalvariable(线程局部变量)。也许把它命名为ThreadLocalVar更加合适。线程局部变量(ThreadLocal)其实的功用非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,是Java中一种较为特殊的线程绑定机制,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。
通俗的讲ThreadLocal本身就是一个Map,通过源码我们可以找到ThreadLocal里面有个内部类:
/**
* ThreadLocalMap is a customized hash map suitable only for
* maintaining thread local values. No operations are exported
* outside of the ThreadLocal class. The class is package private to
* allow declaration of fields in class Thread. To help deal with
* very large and long-lived usages, the hash table entries use
* WeakReferences for keys. However, since reference queues are not
* used, stale entries are guaranteed to be removed only when
* the table starts running out of space.
*/
static class ThreadLocalMap {
......
}
其实构造与hashMap差不多, 唯一的区别就是他的key 是其本身 ThreadLocal,可以通过它的set 方法看出来:
/**
* Set the value associated with key.
*
* @param key the thread local object
* @param value the value to be set
*/
private void set(ThreadLocal<?> key, Object value) {
// We don't use a fast path as with get() because it is at
// least as common to use set() to create new entries as
// it is to replace existing ones, in which case, a fast
// path would fail more often than not.
.......
}
每个线程调用全局的ThreadLocal对象的set方法, 就相当于往其内部的map增加一条记录, key分别是各自的线程, value是各自的set方法传进去的值, 在线程结束时可以调用ThreadLocal的clear方法, 这样会更快的释放内存(规范), 不调用也可以, 因为线程结束后也可以自动释放相关的ThreadLocal的变量(尽量不用, 因为ThreadLocal是弱引用, 可能会导致内容泄漏, 下面会写).
下图是ThreadLocal的对象模型的
一 . ThreadLocal的使用场景:
1. 订单处理包含一系列操作:减少库存量, 增加一条流水台账, 修改总账, 这几个操作需要在同一个事务中完成, 通常也即是同一个线程中处理, 如果累加公司应收款操作失败了, 则应该把前面的操作回滚, 否则提交所有, 这要求这些操作使用相同的数据库连接对象, 而这些操作的代码应该分别位于不同的模块类中.
2.银行转账包含一系列操作, 把传出账户的余额减少, 把转入账户的余额增加, 这两个操作是要同一个事务中完成, 他们必须使用相同的数据库连接, 转入和转出操作的代码分别是两个人不同账户对象的方法.
总结: 一个ThreadLocal 代表一个变量, 故其中只能放一个数据, 如果你有两个变量要共享 , 可以定义一个对象里包含2个变量, 然后在ThreadLocal中存储这个变量, 一个标准的ThreadLocal封装类里(用private static 表示强引用,防止被gc回收), 必须有get方法, set方法, 在线程结束前, 必须调用thread的remove操作.
二、API说明
ThreadLocal()
创建一个线程本地变量。
T get()
返回此线程局部变量的当前线程副本中的值,如果这是线程第一次调用该方法,则创建并初始化此副本。
protected T initialValue()
返回此线程局部变量的当前线程的初始值。最多在每次访问线程来获得每个线程局部变量时调用此方法一次,即线程第一次使用 get() 方法访问变量的时候。如果线程先于 get 方法调用 set(T) 方法,则不会在线程中再调用 initialValue 方法。
若该实现只返回 null;如果程序员希望将线程局部变量初始化为 null 以外的某个值,则必须为 ThreadLocal 创建子类,并重写此方法。通常,将使用匿名内部类。initialValue 的典型实现将调用一个适当的构造方法,并返回新构造的对象。
void remove()
移除此线程局部变量的值。这可能有助于减少线程局部变量的存储需求。如果再次访问此线程局部变量,那么在默认情况下它将拥有其 initialValue。
void set(T value)
将此线程局部变量的当前线程副本中的值设置为指定值。许多应用程序不需要这项功能,它们只依赖于 initialValue() 方法来设置线程局部变量的值。
在程序中一般都重写initialValue方法,以给定一个特定的初始值。
最后传送门: ThreadLocal 安全性和内存泄漏问题以及生产实例