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

java多线程--ThreadLocal类

2015-12-14 14:30 531 查看
1. ThreadLocal类的实现原理

ThreadLocal类是java中一种解决多线程环境下并发问题的新思路,它的原理就是为每一个线程提供一个变量的副本,这样每个线程对变量的修改就不会影响其他线程。

首先看一下ThreadLocal提供的API:

然后看一下ThreadLocal是怎么为每一个线程提供一个副本的:

public T get(){
Thread t = Thread.currentThread();
ThreadLoclMap map = getMap(t);
if(map != null){
ThreadLocalMap.Entry e = map.getEntry(this); //this 指当前的ThreadLocal
if(e != null)
return (T)e.value;
}
return setInitialValue();

}

//getMap()实际是获取Thread对象中的一个threadLocals变量,而该变量的类型是一个ThreadLocalMap 。

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

}

在Thread中的threadLocals变量的定义如下:

ThreadLocal.ThreadLocalMap threadLocls = null;

而ThreadLocalMap 实际上是ThreadLocal的一个内部类它的定义如下:

static class ThreadLocalMap{
static class Entry extends WeakReference<ThreadLocal>{
Object value;
Entry(ThreadLocal k, Object v){
super(k);
value = v;
}
}

}

再看一下setInitialValue()的源码实现:

private T setInitialValue(){
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if(map != null)
map.set(this, value);
else
createMap(t, value);
return value;

}

createMap的实现如下:

void createMap(Thread t, T firstValue){
t.threadLocals = new ThreadLocalMap(this, firstValue);

}

而set()方法实际上就是网当前Thread的ThreadLocalMap类型变量中存值。

从上面的源码可以看出实际上Thread类中有一个ThreadLocalMap类型的变量threadLocals,该变量存储以当前的ThreadLocal对象为key,以要保存的变量的值为value的键值对。而ThreadLocalMap是ThreadLocal的一个内部类,可以把它看做ThreadLocal中的一个Map,当在一个线程中调用ThreadLocal的get方法时,会取得当前线程中的ThreadLocalMap类型变量,如果该变量不为空,且里面有键值对,那么就直接取出该类map中的当前ThreadLocal对象为键锁对应的值,即当前线程中的变量值。如果该变量为空,那么再调用setInitialValue方法为其设置值,前提是重了initialValue方法,如果没有重写该方法,那么默认设置的值为null,如果在new一个ThreadLocal的时候重写了

initialValue方法,在调用setInitialValue就可以取得initialValue的值,现在明白重写initialValue的作用

了吧可以调用set方法设置值,其实设置值得过程就是存储副本的过程归根到底还是靠Thread对象中的类似map功能的ThreadLocalMap类型变量为每个线程存储变量的副本。这样每个线程都存储着一个变量的副本。

2.ThreadLocal的应用实例

public class Student {
private int age = 0;

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

}

public class ThreadLocalTest implements Runnable{
private final static ThreadLocal stucentLocal = new ThreadLocal();

public static void main(String[] args) {
ThreadLocalTest tl = new ThreadLocalTest();
Thread t1 = new Thread(tl, "a");
Thread t2 = new Thread(tl, "b");
t1.start();
t2.start();

}

public void run(){
accessStudent();
}

public void accessStudent(){
String currentThreadName = Thread.currentThread().getName();
System.out.println(currentThreadName + "is running!");
Random r = new Random();
int age = r.nextInt(100);
Student student = getStudent();
student.setAge(age);
System.out.println("thread" + currentThreadName + "first read age is:" + student.getAge());
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}

}

protected Student getStudent(){
Student s = (Student) stucentLocal.get();
if(s == null){
s = new Student();
stucentLocal.set(s);
}
return s;

}

}

输出结果:

a is running!

b is running!

threadafirst read age is:17

threadbfirst read age is:50

可以看出,每个线程都保存自己的student的副本。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java 多线程