ThreadLocal的理解

来源:互联网 发布:我想做淘宝兼职怎么做 编辑:程序博客网 时间:2024/06/05 15:32

ThreadLocal是什么

它的作用是为使用该变量的线程提供一个变量值的副本,每个线程都可以独立的改变自己的副本,而不与其他线程的副本造成冲突。
从线程的角度看,每个线程都保持着一个对其线程局部变量副本的引用,只要是线程是活动的并且线程ThreadLocal实例是可以访问的;在线程消失之后,其线程局部变量的所有副本都会被回收。

通过ThreadLocal存取数据,总是与当前线程有关,也就是说JVM为每个运行的线程,绑定了私有的本地实例存取空间,从而为多线程环境常出现的并发问题提供了一种隔离机制,也就是说采用了以空间换时间的方式,为每一个线程提供了一个变量,因此可以同时访问而互不影响。总结就是提供线程内的·局部变量,这种变量在线程的生命周期内起作用,且在本线程中随时随地可取,隔离其他线程。

在JDBC的实际应用中

public class ManagerThreadLocal{    private static ThreadLoacl<Connection> tl = new ThreadLocal<Connection>();}//得到一个连接public static Connection getConnection(){    Connection conn = tl.getConnection();//从当前的线程取出一个连接    if(conn == null){        conn = C3P0Util.getConnection();        tl.set(conn);    }    return conn;}//开始事物public static void startTransacation(){    try {            Connection conn = getConnection();            conn.setAutoCommit(false);//从当前线程对象中取出的连接,并开始事务        } catch (SQLException e) {            e.printStackTrace();        }}public static void commit(){    try {            getConnection().commit();//提交事务        } catch (SQLException e) {            e.printStackTrace();        }}public static void rollback(){        try {            getConnection().rollback();//回滚事务        } catch (SQLException e) {            e.printStackTrace();        }public static void close(){        try {            getConnection().close();//把连接放回池中            tl.remove();//把当前线程对象中的conn移除        } catch (SQLException e) {            e.printStackTrace();        }    }

原理解释

构造函数
ThreadLocal的构造函数签名是这样的:

public ThreadLocal(){}

内部什么也没做
initialValue函数
该函数用来设置ThreadLocal的初始值,函数签名:

 protected T initialValue() {        return null;    }

该函数在调用get函数的时候会第一次调用,但是如果一开始调用了set函数,则该函数不会被调用。该函数只会被调用一次,但是如果调用了remove函数后,在调用get方法依旧会调用该函数。
get函数
该函数用来获取与当前线程有关联的ThreadLocal的值,该值如下
public T get()
如果当前线程没有ThreadLocal的值,则调用initialValue方法后返回null
set函数
set函数用来设置当前线程的该ThreadLocal函数获取返回值返回。
public void set(T value)
设置当前线程的ThreadLocal的值为value
remove函数
remove函数用来将当前线程的ThreadLocal绑定的值删除,函数签名如下:
public void remove()
如何实现
最简单的思想是:每个Thread类创建一个map,然后用线程的Id作为Map的key,实例对象作为Map的value,这样就能达到线程隔离的效果。
get的流程:

1.首先要获得当前线程
2.根据当前线程获取一个Map
3.如果Map不是空,则在Map中一ThreadLocal的引用来在key获取响应value,否则转到5
4.如果e不为null,则返回e.value,否则跳到5
5.Map为空或者e为空,则通过initialValue函数获取初始值value,然后用ThreadLocal的引用和value作为firstKey和firstValue创建一个新的Map。

总结设计思路:

每个Thread维护一个ThreadLocalMap映射表,这个映射表的key是ThreadLocal实例本身,value是真正需要存储的Object。

设计原因:
当Thread销毁之后对应的ThreadLocalMap也就销毁,减少了内存使用