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的作用

猜你喜欢

转载自blog.csdn.net/zpzkitt/article/details/89160175
今日推荐