关于java并发编程的相关文章都是阅读了《java并发编程实战》以后的读书笔记总结java
ThreadLocal实际上是线程封闭的一种规范化的实现,它经过提供一组get和set的接口为每一个使用该变量的线程保存一份独立的副本。对于那种按线程多实例(每一个线程对应一个实例)的对象的访问,而且这个对象不少地方都要用到的状况(例如数据库链接管理、会话session管理以及线程私有的消息队列等),ThreadLocal就会展示出它的魅力。数据库
下面的这个小例子展现了ThreadLocal的常规使用:编程
public class ThreadResource {
private String threadName;
private int threadId;
public ThreadResource(int threadId, String threadName) {
this.threadId = threadId;
this.threadName = threadName;
}
public String getThreadName() {
return threadName;
}
public void setThreadName(String threadName) {
this.threadName = threadName;
}
public int getThreadId() {
return threadId;
}
public void setThreadId(int threadId) {
this.threadId = threadId;
}
}
public class Test {
//以一个静态实例的方式持有一个ThreadLocal对象,它里面以map的形式存储了线程的局部变量
static ThreadLocal<ThreadResource> resoursePackage = new ThreadLocal<ThreadResource>() {
@Override
protected ThreadResource initialValue() {
return new ThreadResource(0, "initialThread");
}
};
private static class TestThread extends Thread {
@Override
public void run() {
resoursePackage.set(new ThreadResource(1, "testThread"));
System.out.println(resoursePackage.get().getThreadName() + resoursePackage.get().getThreadId());
}
}
public static void main(String[] args) {
System.out.println(resoursePackage.get().getThreadName() + resoursePackage.get().getThreadId());
new TestThread().start();
}
}复制代码
public T get() {
//获取当前threadlocal变量所属的线程
Thread t = Thread.currentThread();
//根据线程获取到一个ThreadLocalMap的对象
ThreadLocalMap map = getMap(t);
//若是线程已经绑定了一个ThreadLocalMap对象的话,则从中获取到里面所保存的值,不然使用初始化的值
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T) e.value;
return result;
}
}
return setInitialValue();
}复制代码
咱们看一下上面getMap()的方法的实现session
ThreadLocalMap getMap(Thread t) {
//返回线程的一个ThreadLocalMap的成员变量,下面是该成员变量在threa类中的声明
//ThreadLocal values pertaining to this thread. This map is maintained by the ThreadLocal class.
//ThreadLocal.ThreadLocalMap threadLocals = ull;
return t.threadLocals;
}复制代码
再看一下线程还没有绑定ThreadLocalMap对象的时候,调用的 setInitialValue() 的方法的实现并发
private T setInitialValue() {
//initialValue()就是咱们在新建一个ThreadLocal变量的时候,实现的protected的那个方法。
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
//由此咱们可知,线程还没有绑定到ThreadLocalMap对象的时候
//ThreadLocal为咱们使用在initialValue设置的值初始化了一个对象值,并绑定到该线程上。
createMap(t, value);
return value;
}复制代码
在上面的代码中,咱们一直说起到了一个ThreadLocalMap的类,它实际上是在ThreadLocal的一个静态内部类,它是一个ThreadLocal自定义的hash map对象,用于保存线程的局部变量。在它里面,又包含了一个Entry的静态内部类,它里面就是对应的所要存储的值。咱们看一下源码的实现ide
static class ThreadLocalMap {
static class Entry extends WeakReference<ThreadLocal<?>> {
Object value;
//以ThreadLocal对象做为键值,保存threadlocal变量所包含的值
//咱们在ThreadLocal的get方法当中也是根据threadlocal变量取出所存储的值
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
}复制代码
public void set(T value) {
//获取threadlocal对象所属的线程
Thread t = Thread.currentThread();
//获取线程所绑定的ThreadLocalMap对象
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
//在线程还没有初始化并绑定ThreadLocalMap对象的时候,使用给定的value值新建一个,并将线程与该对对象关联起来
createMap(t, value);
}复制代码
在阅读了上面的源码以后,咱们大概已经明白了ThreadLocal是怎么作到为每一个线程保存一份引用对象的拷贝的值的。每一个thread对象都会持有一个ThreadLocal.ThreadLocalMap的对象的引用,而咱们经过ThreadLocal对象找到了线程所持有的这个ThreadLocalMap对象,并往其中添加、移除或得到咱们所要保存的引用对象的值。this
关于ThreadLocalMap里面实现的自定义的hash map咱们能够在ThreadLocal的源码中深刻了解,这里不作进一步的深刻。spa