您的位置:首页 > 编程语言 > Java开发

JDK源码解析--- ThreadLocal

2018-01-04 10:22 316 查看
说明:本文是JDK 1.8版本

1.简介:

ThreadLocal 又叫做线程本地变量,也被称为线程本地存储。ThreadLocal 为 变量 在每一个线程中创建 一个 副本(不是原来变量的引用),每一个线程都会独自拥有变量副本,而不会相互影响。

2.实现方式:

(1)set 方法,,因为线程Thread 类中 内置了 ThreadLocal.ThreadLocalMap 类型的引用threadLocals,所以 set方法把把 用户变量 存储到线程的 变量threadLocals中

public void set(T value) {
Thread t = Thread.currentThread();//得到当前线程
ThreadLocalMap map = getMap(t);//得到线程中 threadLocals的值
if (map != null)
map.set(this, value);//如果当前不为空则设置 键值对,键为 当前的ThreadLocal
else
createMap(t, value);//如果为空则创建一个ThreadLocalMap
}


ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}


void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue); //把用户变量 存放到 线程中
}

ThreadLocalMap 里面 使用了Entry 存储数据,键 为 ThreadLocal,值为用户变量

static class ThreadLocalMap {

static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;

Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}


(2) get方法,获取当前线程中存储的用户变量

public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);//得到当前线程中存储的用户变量
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);//得到指定 ThreadLocalMap的 存储的用户变量值
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();//设置初始化的值
}


private T setInitialValue() {
T value = initialValue();//默认返回为null ,用户可以重写 改方法,实现自己想要的结果
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t); //得到当前 线程的 本地变量值
if (map != null)
map.set(this, value); // 如果线程中存在 ThreadLocalMap存在 则 存储 用户变量到线程
else
createMap(t, value); //如果不存在 则新增一个到当前线程中
return value;
}


protected T initialValue() {
return null;
}


3.代码验证 用户变量是否存放到 线程中:

方式一:不重写initialValue方法

public class ThreadLocalDemo1 {
ThreadLocal<String> stringThreadLocal = new ThreadLocal<String>();
ThreadLocal<Long> longThreadLocal = new ThreadLocal<Long>();
public  void set(){
stringThreadLocal.set(Thread.currentThread().getName());
longThreadLocal.set(Thread.currentThread().getId());
}
public void show(){
System.out.println(longThreadLocal.get());
System.out.println(stringThreadLocal.get());
}

public static void main(String[] args) throws Exception{
ThreadLocalDemo1 demo1 = new ThreadLocalDemo1();
demo1.set();
demo1.show();
Thread t = new Thread(){
@Override
public void run() {
demo1.set();
demo1.show();
}
};
t.start();
t.join();
demo1.show();
}
}

输出结果:

1

main

11

Thread-0

1

main

在线程t 没创建之前,存放在线程main 函数中,而线程 t 中 又重新赋值,输出显示的是一个新的 线程, 在线程结束 之后,直接输出 ,仍然是进入线程

之前存放的值,因此可以看到 他们是 在每个线程中 创建了副本

方式二:重写initialValue方法

public class ThreadLocalDemo2 {
ThreadLocal<String> stringThreadLocal = new ThreadLocal<String>(){
@Override
protected String initialValue() {
return Thread.currentThread().getName();
}
};
ThreadLocal<Long> longThreadLocal = new ThreadLocal<Long>(){
@Override
protected Long initialValue() {
return Thread.currentThread().getId();
}
};

public void show(){
System.out.println(longThreadLocal.get());
System.out.println(stringThreadLocal.get());
}

public static void main(String[] args) throws Exception{
ThreadLocalDemo2 demo1 = new ThreadLocalDemo2();

demo1.show();
Thread t = new Thread(){
@Override
public void run() {
demo1.show();
}
};
t.start();
t.join();
demo1.show();
}
}


输出结果:

1

main

11

Thread-0

1

main

ThreadLocal 经常在管理数据库连接,session 管理 中使用 :

使用场景的代码摘抄自(摘抄自:http://www.importnew.com/17849.html)

private static ThreadLocal<Connection> connectionHolder
= new ThreadLocal<Connection>() {
public Connection initialValue() {
return DriverManager.getConnection(DB_URL);
}
};


private static final ThreadLocal threadSession = new ThreadLocal();

public static Session getSession() throws InfrastructureException {
Session s = (Session) threadSession.get();
try {
if (s == null) {
s = getSessionFactory().openSession();
threadSession.set(s);
}
} catch (HibernateException ex) {
throw new InfrastructureException(ex);
}
return s;
}


参考博客:
http://www.importnew.com/17849.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: