【SharingObjects】ThreadLocal

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】

描述

该类提供了线程局部(thread-local)变量。这些变量不同于它们的普通对应物,因为访问某个变量(通过其get或set方法)的每个线程都有自己的局部变量,它独立于变量的初始化副本。ThreadLocal实例通常是类中的private static字段,它们希望将状态与某一个线程(例如,用户ID或事物ID)相关联。

场景

适用于无状态,副本变量独立后不影响业务逻辑的高并发场景。
Hibernate的session获取场景

    private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();

    //获取Session
    public static Session getCurrentSession(){
        Session session =  threadLocal.get();
        //判断Session是否为空,如果为空,将创建一个session,并设置到本地线程变量中
        try {
            if(session ==null&&!session.isOpen()){
                if(sessionFactory==null){
                    rbuildSessionFactory();// 创建Hibernate的SessionFactory
                }else{
                    session = sessionFactory.openSession();
                }
            }
            threadLocal.set(session);
        } catch (Exception e) {
            // TODO: handle exception
        }

        return session;
    }

使用ThreadLocal的典型场景正如上面的数据库连接管理,线程会话管理等场景,只适用于独立变量副本的情况,如果变量为全局共享的,则不适用在高并发下使用。

源码分析

静态内部类ThreadLocalMap

其内部的Entry的key通过弱引用包装,当垃圾回收时,如果其强引用的值没有被释放,则会发生内存溢出。使用完ThreadLocal之后,记得调用remove方法。

      /**
             * The entries in this hash map extend WeakReference, using
             * its main ref field as the key (which is always a
             * ThreadLocal object).  Note that null keys (i.e. entry.get()
             * == null) mean that the key is no longer referenced, so the
             * entry can be expunged from table.  Such entries are referred to
             * as "stale entries" in the code that follows.
             */
            static class Entry extends WeakReference<ThreadLocal<?>> {
                /**
                 * The value associated with this ThreadLocal.
                 */
                Object value;

                Entry(ThreadLocal<?> k, Object v) {
                    super(k);
                    value = v;
                }
            }

get()

      /**
         * Returns the value in the current thread's copy of this
         * thread-local variable.  If the variable has no value for the
         * current thread, it is first initialized to the value returned
         * by an invocation of the {@link #initialValue} method.
         * 返回当前线程的内部变量副本,如果没有就返回变量的初始值
         *
         * @return the current thread's value of this thread-local
         */
        public T get() {
            //获取当前线程
            Thread t = Thread.currentThread();
            //获取此线程相关联的ThreadLocal,entry的key为WeakReference,值为强引用,注意内存溢出。
            ThreadLocalMap map = getMap(t);
            //如果存在值,就返回
            if (map != null) {
                ThreadLocalMap.Entry e = map.getEntry(this);
                if (e != null) {
                    @SuppressWarnings("unchecked")
                    T result = (T) e.value;
                    return result;
                }
            }
            //不存在就返回初始值,并设置ThreadLocalMap映射
            return setInitialValue();
        }
     /**
         * Variant of set() to establish initialValue. Used instead
         * of set() in case user has overridden the set() method.
         *
         * @return the initial value
         */
        private T setInitialValue() {
            //获取初始值
            T value = initialValue();
            //当前线程
            Thread t = Thread.currentThread();
            //获取当前线程映射
            ThreadLocalMap map = getMap(t);
            //有的话就设置初始值,没有的话新建map
            if (map != null)
                map.set(this, value);
            else
                createMap(t, value);
            //返回初始值
            return value;
        }

set()

      /**
         * Sets the current thread's copy of this thread-local variable
         * to the specified value.  Most subclasses will have no need to
         * override this method, relying solely on the {@link #initialValue}
         * method to set the values of thread-locals.
         *
         * @param value the value to be stored in the current thread's copy of
         *              this thread-local.
         */
        public void set(T value) {
            Thread t = Thread.currentThread();
            ThreadLocalMap map = getMap(t);
            if (map != null)
                map.set(this, value);
            else
                createMap(t, value);
        }

remove()

将当前线程局部变量的值删除,目的是为了减少内存的占用,该方法是JDK 5.0新增的方法。当线程结束后,对应该线程的局部变量将被自动垃圾回收,所以显示调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度;

initialValue()

返回该线程局部变量的初始值,该方法是一个protected的方法,显然是为了让子类覆盖而设计的,这个方法是一个延迟调用方法,在线程第1次调用get()或set(T)时才执行,并且仅执行1次。ThreadLocal中的默认实现直接返回一个null。


来源:https://www.jianshu.com/p/347ea7f881f8

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » 【SharingObjects】ThreadLocal

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏