java ThreadLocal深入分析
一、ThreadLocal是什么
平时使用最多的应该是局部变量和全局变量,threadlocal就可以看成是一个局部变量生产工厂,这个类型局部变量在很多未知的线程中都会用到。
二、ThreadLocal怎么用
threadlocal在初始化的时候回创建一个局部ThreadLocalMap对象,因为每个线程都这个对象只是值为null,当需要的时候就可以初始化使用,ThreadLocalMap是ThreadLocal的内部静态类,ThreadLocalMap里面还有一个继承WeakReference的Entry静态内部类。
在创建新的map时就是通过ThreadLocalMap保存线程对应的变量的,map的key是当前线程对象,value就是保存的value。ThreadLocalMap就可以看成一个普通的map结构,跟hashmap类似。
static class ThreadLocalMap {
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
private Entry[] table;
private int size = 0;
。。。
}
threadlocal的方法:
public T get(); //1
public void set(T value); //2
public void remove(); //3
protected T initialValue(); //4
public static <S> ThreadLocal<S> withInitial(Supplier<? extends S> supplier); //5
1、get方法是获取threadlocal里的值,也就是模板的T。
2、set方法是设置value值,通常是先set一个value然后再get
3、remove释放资源,threadlocal的资源是会自动释放的,随着线程的结束就会被回收,但是调用remove会更快释放
4、初始化数据,这是一个protected方法,是为了子类覆盖重新实现的,原始提供的返回null,可以覆盖之后返回一个默认值,这样在没有set之前就get会取到默认值
5、这是1.8新出的一个函数式接口Supplier,就是创建对象的工厂,这里就是创建threadlocal对象,具体可以看函数式接口用法
三、ThreadLocal存在的意义
就拿web后台中的service和dao之间的关系举例,一个初级水平的代码是这样的
service层代码
public void serviceMethod(){
Connection conn=null;
try{
Connection conn=getConnection();
conn.setAutoCommit(false);
Dao1 dao1=new Dao1(conn);
dao1.doSomething();
Dao2 dao2=new Dao2(conn);
dao2.doSomething();
Dao3 dao3=new Dao3(conn);
dao3.doSomething();
conn.commit();
}catch(Exception e){
try{
conn.rollback();
}catch(Exception ex){}
}finally{
try{
conn.setAutoCommit(true);
}catch(Exception e){}
try{
if(conn!=null){
conn.close();
conn=null;
}
}catch(Exception e){}
}
}
Dao层代码
class Dao1{
private Connection conn=null;
public Dao1(Connection conn){
this.conn=conn;
}
public void doSomething(){
PreparedStatement pstmt=null;
try{
pstmt=conn.preparedStatement(sql);
pstmt.execute…
…
}catch(Exception e){
log.error(e,”Exeception occurred in Dao1.doSomething():”+e.getMessage,e);
}finally{
try{
if(pstmt!=null){
pstmt.close();
pstmt=null;
}
}catch(Exception e){}
}
}
}
这样的service和dao的connection传递就会造成耦合,破坏了OOP的封装特性。所以在spring中就用到了面向切面编程(AOP)的思想。
public void serviceMethod(){
try{
//aop 自动加入connection,并且将conn.setAutoCommit(false);
dao1.doSomething();
dao2.doSomething();
dao3.doSomething();
}catch(Exception e){
//aop 自动加入rollback
}finally{
//aop自动加入conn.setAutoCommit(true)
//aop 自动加入conn.close();
}
画了一张图来表示Threadlocal的作用