Java并发编程-04-线程局部变量

来源:互联网 发布:环境测试仪单片机包装 编辑:程序博客网 时间:2024/05/02 16:59

一、线程局部变量

1、如果一个变量是成员变量,那么多个线程对同一个对象的成员变量进行操作时,它们对该成员变量是彼此影响的,也就是说一个线程对成员变量的改变会影响到另一个线程。

2、在某种情况下,对象的属性不需要被所有线程共享。可以采用 Java api 提供的一个干净的机制-----线程局部变量 <Thread -Local Variable>

3、如果一个变量是局部变量,那么每个线程都会有一个该局部变量的拷贝(即便是同一个对象中的方法的局部变量,也会对每一个线程有一个拷贝),一个线程对该局部变量的改变不会影响到其他线程

二、ThreadLocal

1、ThreadLocal提供的方法

public T get() { } //用来获取ThreadLocal在当前线程中保存的变量副本public void set(T value) { } //set()用来设置当前线程中变量的副本public void remove() { } //用来移除当前线程中变量的副本protected T initialValue() { } //是一个protected方法,一般是用来在使用时进行重写的,它是一个延迟加载方法

2、ThreadLocal的使用场景:数据库连接、Session管理等。

3、ThreadLocal是如何做到为每一个线程维护变量的副本的呢?----使用map

对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。

4、查看源码

public T get() {        Thread t = Thread.currentThread(); //获取当前线程        ThreadLocalMap map = getMap(t); //获取一个map,map的类型为ThreadLocalMap。        if (map != null) {            ThreadLocalMap.Entry e = map.getEntry(this); //获取到<key,value>键值对,注意这里获取键值对传进去的是  this,而不是当前线程t。            if (e != null) { //如果获取成功,则返回value值                @SuppressWarnings("unchecked")                T result = (T)e.value;                return result;            }        }        return setInitialValue(); //map为空,则调用setInitialValue方法返回value    }


GetMap怎么实现的?
//getMap干了什么?ThreadLocalMap getMap(Thread t) {        return t.threadLocals;//调用当期线程t,返回当前线程t中的一个成员变量threadLocals    }


threadLocals是什么?

 //threadLocals是什么?实际上就是一个ThreadLocalMap,这个类型是ThreadLocal类的一个内部类    ThreadLocal.ThreadLocalMap threadLocals = null;

5、原理

首先,Thread这个类有一个ThreadLocal.ThreadLocalMap类型的成员变量threadLocals,

ThreadLocal.ThreadLocalMap threadLocals = null;

这个threadLocals就是用来存储实际的变量副本的,键值为当前ThreadLocal变量,value为变量副本(即T类型的变量)。初始时,在Thread里面,threadLocals为空,当通过ThreadLocal变量调用get()方法或者set()方法,就会对Thread类中的threadLocals进行初始化,并且以当前ThreadLocal变量为键值,以ThreadLocal要保存的副本变量为value,存到threadLocals。然后在当前线程里面,如果要使用副本变量,就可以通过get方法在threadLocals里面查找

三、使用实例

// 声明一个ThreadLocal<Date>对象,这个对象是在initialValue()方法中隐式实现的private ThreadLocal<Date> startDate = new ThreadLocal<Date>() {protected Date initialValue() {return new Date();};};



0 0
原创粉丝点击