ThreadLocal
类 ThreadLocal<T>在java.lang包下,jdk1.2提供的方法,1.5后实现的泛型。
官方文档:
该类提供了线程局部 (thread-local) 变量。这些变量不同于它们的普通对应物,因为访问某个变量(通过其 get 或 set 方法)的每个线程都有自己的局部变量,它独立于变量的初始化副本。ThreadLocal 实例通常是类中的 private static 字段,它们希望将状态与某一个线程(例如,用户 ID 或事务 ID)相关联。
例如,以下类生成对每个线程唯一的局部标识符。线程 ID 是在第一次调用 UniqueThreadIdGenerator.getCurrentThreadId() 时分配的,在后续调用中不会更改。
import java.util.concurrent.atomic.AtomicInteger;
public class UniqueThreadIdGenerator {
private static final AtomicInteger uniqueId = new AtomicInteger(0);
private static final ThreadLocal < Integer > uniqueNum =
new ThreadLocal < Integer > () {
@Override protected Integer initialValue() {
return uniqueId.getAndIncrement();
}
};
public static int getCurrentThreadId() {
return uniqueId.get();
}
} // UniqueThreadIdGenerator
每个线程都保持对其线程局部变量副本的隐式引用,只要线程是活动的并且 ThreadLocal 实例是可访问的;在线程消失之后,其线程局部实例的所有副本都会被垃圾回收(除非存在对这些副本的其他引用)。
理解ThreadLocal
在java开发中,我们很多地方会用到多线程,但是在有些情况下,我们需要在多线程处理过程中的每一个线程单独持有一个特定的对象,并且在操作中进行使用。此时我们就需要该对象就像一个线程的属性一样,能够在各自线程中进行设置与取出或者更改。
此时sun公司提供了ThreadLocal类:
public ThreadLocal()
//创建一个线程本地变量。
protected T initialValue()//通过这个方法设置一个默认的值
//返回此线程局部变量的当前线程的“初始值”。线程第一次使用 get() 方法访问变量时将调用此方法,但如果线程之前调用了 set(T) 方法,则不会对该线程再调用 initialValue 方法。通常,此方法对每个线程最多调用一次,但如果在调用 get() 后又调用了 remove(),则可能再次调用此方法。
该实现返回 null;如果程序员希望线程局部变量具有 null 以外的值,则必须为 ThreadLocal 创建子类,并重写此方法。通常将使用匿名内部类完成此操作。
返回:
返回此线程局部变量的初始值
public T get()
//返回此线程局部变量的当前线程副本中的值。如果变量没有用于当前线程的值,则先将其初始化为调用 initialValue() 方法返回的值。
返回:
此线程局部变量的当前线程的值
public void set(T value)
//将此线程局部变量的当前线程副本中的值设置为指定值。大部分子类不需要重写此方法,它们只依靠 initialValue() 方法来设置线程局部变量的值。
参数:
value - 存储在此线程局部变量的当前线程副本中的值。
public void remove()//jdk1.5后支持
//移除此线程局部变量当前线程的值。如果此线程局部变量随后被当前线程读取,且这期间当前线程没有设置其值,则将调用其 initialValue() 方法重新初始化其值。这将导致在当前线程多次调用 initialValue 方法。
Demo
//eg:1
private static ThreadLocal<Boolean> hasTran_Local = new ThreadLocal<Boolean>() {
protected Boolean initialValue() {
return false;
};
};
//这里定义了一个ThreadLocal对象hasTran_Local,通过initialValue方法设置了初始值为false,并且可以在线程运行过程中通过set方法进行更改。通过get方法能够得到只属于这个线程的一个boolean值。
//eg:2
private static ThreadLocal<Connection> conn_local = new ThreadLocal<Connection>() {
@Override
protected Connection initialValue() {
return DaoUtils.getConn();
}
};
//这里定义了一个ThreadLocal对象conn_local,在本线程中通过get方法能够得到Connection对象,由于线程第一次使用 get() 方法访问变量时将调用initialValue方法,所以在一个线程中得到的connection是同一个。
这个方法也能解决JavaEE分层带来的数据库事物操作的问题。