1、ThreadLocal类简介:
ThreadLocal被称为线程局部变量。也是实现共享变量数据一致性的一种方式,与Synchronized相比较,使用ThreadLocal是以空间换时间。当使用ThreadLocal维护变量时,访问其中的每个线程(通过其 get或set方法)具有其自己的,独立初始化的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。实现副本的方式主要是通过ThreadLocalMap这个静态内部类,可以简单的理解为这内部类中有一个table数组,这个table数组中的每个元素都可以简单理解为(key,value)对,key是ThreadLocal类型,value是object类型。在Thread类中又存在一个ThreadLocal.ThreadLocalMap类型的变量threadLocals 。可以理解为,ThreadLocal类将当前线程的一种唯一标识(与ThreadLocal类相关)作为一个map的key,将共享变量的副本作为value存储。每次调用get方法时,都是通过当前线程对应的唯一标识查询出存储的value。不同的线程由于标识不同,每个线程存储的变量副本位置也不一样,互不干涉。
2、ThreadLocal类的get、set等方法的实现及介绍:
(1)get方法:返回当前线程的此线程局部变量副本中的值。如果变量没有当前线程的值,则首先将其初始化为调用initialValue()方法返回的值。
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
(2)set方法:将此线程局部变量的当前线程副本设置为指定值。大多数子类都不需要重写此方法,仅依靠initialValue() 方法来设置线程局部的值。
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
(3)initialValue方法:返回此线程局部变量的当前线程的“初始值”。这个实现简单地返回null; 如果程序员希望线程局部变量具有除了null以外的初始值,则ThreadLocal必须进行子类化,并且重写此方法。通常,将使用匿名内部类。
protected T initialValue() {
return null;
}
(4)remove方法:删除此线程局部变量的当前线程值。如果当前线程随后读取此线程局部变量 ,则将通过调用其initialValue方法重新初始化其值,除非其值由临时的当前线程设置。这可能导致在initialValue当前线程中多次调用该方法。
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
}
3、ThreadLocal类的简单使用:
import java.util.concurrent.TimeUnit;
public class TestThreadLocal {
public static void main(String[] args) {
//将值初始化0
ThreadLocal<Integer> threadLocal=new ThreadLocal<Integer>(){
@Override
protected Integer initialValue() {
return 0;
}
};
//线程一
new Thread(new Runnable() {
@Override
public void run() {
threadLocal.set(1);
System.out.println(Thread.currentThread().getName()+" set "+1);
//睡眠一秒,让线程3执行完成
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" get "+threadLocal.get());
}
},"thread 1").start();
//线程二
new Thread(new Runnable() {
@Override
public void run() {
threadLocal.set(2);
System.out.println(Thread.currentThread().getName()+" set "+2);
//睡眠一秒,让线程3执行完成
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" get "+threadLocal.get());
}
},"thread 2").start();
//线程三修改ThreadLocal中的值,看线程一和线程二获取到的值是否会与其设置的值不同
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+" start.....");
threadLocal.set(100);//将值设置为100
System.out.println(Thread.currentThread().getName()+" end.....");
}
},"thread 3").start();
}
}
运行结果:
thread 1 set 1
thread 2 set 2
thread 3 start…
thread 3 end…
thread 1 get 1
thread 2 get 2
结果表明在线程3中重新设置ThreadLocal的值,对线程一与线程二获取到的值没有影响以及线程一与线程之间也互不影响。