使用ThreadLocal类型变量初始化的方式:第一个方式为在线程执行方法run()里,变量显示调用set()方法,为该变量赋值;第二个方式为使用匿名内部类的方式,重写ThreadLocal的initialValue()进行初始化。
原因:
1、initialValue()方法默认返回值为null
2、线程启动后,如果方法中使用了ThreadLocal类型变量,调用get()方法获取变量值,实际会调用initialValue方法
3、如果线程中ThreadLocal类型变量先于 get 方法调用 set(T) 方法,则不会在线程中再调用 initialValue 方法。
以上内容可以查看java.lang.ThreadLocal类的源代码,解释的很清楚。
通过查看源码还可以发现:
1、线程局部变量,内部实际上是隶属于当前线程对象的一个map集合,这个集合是当前线程对象的一个成员属性
2、线程局部变量对象就是这个map的key,比如threadlocal对象,value值可以任意类型
基于以上的两种方式,来实现ThreadLocal变量的使用:
方式一步骤:
1、在多线程的类(如ThreadDemo类)中,创建一个ThreadLocal对象threadXxx,用来保存线程间需要隔离处理的对象xxx。
2、在ThreadDemo类中,创建一个获取要隔离访问的数据的方法getXxx(),在方法中判断,若ThreadLocal对象为null时候,应该new()一个隔离访问类型的对象xxx,并执行ThreadLocal对象的set(xxx)。
3、在ThreadDemo类的run()方法中,通过getXxx()方法获取要操作的数据,这样可以保证每个线程对应一个数据对象,在任何时刻都操作的是这个对象。
代码如下:
public class ThreadLocalDemo implements Runnable {
//(1)创建线程局部变量studentLocal,在后面你会发现用来保存Student对象
private final static ThreadLocal<Student> studentLocal = new ThreadLocal<Student>();
public void run() {
//(3)获取一个Student对象,并将随机数年龄插入到对象属性中
Student student = getStudent();
}
//(2)
protected Student getStudent() {
//获取本地线程变量并强制转换为Student类型
Student student = (Student) studentLocal.get();
//线程首次执行此方法的时候,studentLocal.get()肯定为null
if (student == null) {
//创建一个Student对象,并保存到本地线程变量studentLocal中
student = new Student();
studentLocal.set(student);
}
return student;
}
//主方法测试
public static void main(String[] agrs) {
ThreadLocalDemo td = new ThreadLocalDemo();
new Thread(td).start();
new Thread(td).start();
}
}
方式二:希望将线程局部变量初始化为 null 以外的某个值,则必须为 ThreadLocal 创建子类,并重写此方法。通常,将使用匿名内部类。initialValue 的典型实现将调用一个适当的构造方法,并返回新构造的对象。形式:ThreadLocal<T> xxx = new ThreadLocal<T>({重写initialValue()});
代码如下:
private ThreadLocal<Student> studentLocal = new ThreadLocal<Student>(){
//匿名内部类方式,重写initialValue()方法,如果该变量先于 get 方法调用 set(T) 方法,则不会执行重写的该方法
@Override
protected Student initialValue(){
System.out.println("如果调用get方法时还未调用set(T)方法,此方法才会被执行");
return new Student();
}
};
参考:
http://blog.youkuaiyun.com/yanwushu/article/details/7578097
http://my.oschina.net/lichhao/blog/111362
原因:
1、initialValue()方法默认返回值为null
2、线程启动后,如果方法中使用了ThreadLocal类型变量,调用get()方法获取变量值,实际会调用initialValue方法
3、如果线程中ThreadLocal类型变量先于 get 方法调用 set(T) 方法,则不会在线程中再调用 initialValue 方法。
以上内容可以查看java.lang.ThreadLocal类的源代码,解释的很清楚。
贴一段源码看看:
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
return (T)e.value;
}
return 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;
}
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
ThreadLocal.ThreadLocalMap threadLocals = null;
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
通过查看源码还可以发现:
1、线程局部变量,内部实际上是隶属于当前线程对象的一个map集合,这个集合是当前线程对象的一个成员属性
2、线程局部变量对象就是这个map的key,比如threadlocal对象,value值可以任意类型
基于以上的两种方式,来实现ThreadLocal变量的使用:
方式一步骤:
1、在多线程的类(如ThreadDemo类)中,创建一个ThreadLocal对象threadXxx,用来保存线程间需要隔离处理的对象xxx。
2、在ThreadDemo类中,创建一个获取要隔离访问的数据的方法getXxx(),在方法中判断,若ThreadLocal对象为null时候,应该new()一个隔离访问类型的对象xxx,并执行ThreadLocal对象的set(xxx)。
3、在ThreadDemo类的run()方法中,通过getXxx()方法获取要操作的数据,这样可以保证每个线程对应一个数据对象,在任何时刻都操作的是这个对象。
代码如下:
public class ThreadLocalDemo implements Runnable {
//(1)创建线程局部变量studentLocal,在后面你会发现用来保存Student对象
private final static ThreadLocal<Student> studentLocal = new ThreadLocal<Student>();
public void run() {
//(3)获取一个Student对象,并将随机数年龄插入到对象属性中
Student student = getStudent();
}
//(2)
protected Student getStudent() {
//获取本地线程变量并强制转换为Student类型
Student student = (Student) studentLocal.get();
//线程首次执行此方法的时候,studentLocal.get()肯定为null
if (student == null) {
//创建一个Student对象,并保存到本地线程变量studentLocal中
student = new Student();
studentLocal.set(student);
}
return student;
}
//主方法测试
public static void main(String[] agrs) {
ThreadLocalDemo td = new ThreadLocalDemo();
new Thread(td).start();
new Thread(td).start();
}
}
方式二:希望将线程局部变量初始化为 null 以外的某个值,则必须为 ThreadLocal 创建子类,并重写此方法。通常,将使用匿名内部类。initialValue 的典型实现将调用一个适当的构造方法,并返回新构造的对象。形式:ThreadLocal<T> xxx = new ThreadLocal<T>({重写initialValue()});
代码如下:
private ThreadLocal<Student> studentLocal = new ThreadLocal<Student>(){
//匿名内部类方式,重写initialValue()方法,如果该变量先于 get 方法调用 set(T) 方法,则不会执行重写的该方法
@Override
protected Student initialValue(){
System.out.println("如果调用get方法时还未调用set(T)方法,此方法才会被执行");
return new Student();
}
};
参考:
http://blog.youkuaiyun.com/yanwushu/article/details/7578097
http://my.oschina.net/lichhao/blog/111362