java多线程--ThreadLocal类

1. ThreadLocal类的实现原理

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

首先看一下ThreadLocal提供的API:

public T get() { } //返回当前线程中变量的副本值。
public void set(T value) { } //设置当前线程的变量副本的值。
public void remove() { } //移除当前线程变量的值。
protected T initialValue() { } //放回当前线程变量副本的初始值,是一个延迟加载方法,一般重写此方法。

然后看一下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的副本。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值