本地局部变量ThreadLocal的使用

本文介绍了ThreadLocal的基本使用方法,包括在线程执行方法run()里直接为变量赋值和使用匿名内部类重写initialValue()方法进行初始化两种方式。并详细解释了这两种方式的工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用ThreadLocal类型变量初始化的方式:第一个方式为在线程执行方法run()里,变量显示调用set()方法,为该变量赋值;第二个方式为使用匿名内部类的方式,重写ThreadLocal的initialValue()进行初始化。
原因:
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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值