ThreadLocal浅析

一.ThreadLocal简介

1.ThreadLocal是用来存储线程级别的变量的,他的目的是降低同一个变量在同一个线程里面来回切换造成的开销。他存储的变量是绝对的线程安全的,一般我们在实在的应用中用在回话session里面比较多:代码如下

private static final ThreadLocal threadSession = new ThreadLocal();
public static Session getSession() throws InfrastructureException {
Session s = (Session) threadSession.get();
try {
}
if (s == null) {
}
s = getSessionFactory().openSession();
threadSession.set(s);
} catch (HibernateException ex) {
throw new InfrastructureException(ex);
return s;
}

同一个线程里面只需要通过getSession()就可以获取到session

二.为什么是绝对线程安全的?

1.首先我们来看看java.lang.ThreadLocal里面的set方法,源码如下:

 public void set(T value) {
        //1.首先他会先获取当前的线程
        Thread t = Thread.currentThread();
        //2.接着就是获取Thread的一个ThreadLocalMap
        ThreadLocalMap map = getMap(t);
        if (map != null)
           //3.会把ThreadLoacl作为key,将value存放景区
            map.set(this, value);
        else
            createMap(t, value);
    }
 private void set(ThreadLocal<?> key, Object value) {

            // We don't use a fast path as with get() because it is at
            // least as common to use set() to create new entries as
            // it is to replace existing ones, in which case, a fast
            // path would fail more often than not.

            Entry[] tab = table;
            int len = tab.length;
            int i = key.threadLocalHashCode & (len-1);

            for (Entry e = tab[i];
                 e != null;
                 e = tab[i = nextIndex(i, len)]) {
                ThreadLocal<?> k = e.get();

                if (k == key) {
                    e.value = value;
                    return;
                }

                if (k == null) {
                    replaceStaleEntry(key, value, i);
                    return;
                }
            }

            tab[i] = new Entry(key, value);
            int sz = ++size;
            if (!cleanSomeSlots(i, sz) && sz >= threshold)
                rehash();
        }

设置值得过程不可能存在线程安全的问题,因为不可能存在别的线程,来获取这个线程ThreadLocalMap
2.接着我们来看看java.lang.ThreadLocal里面的get方法,源码如下:

 public T get() {
       //1.首先取到当前线程
        Thread t = Thread.currentThread();
        //取到当前线程的ThreadLocalMap
        ThreadLocalMap map = getMap(t);
        if (map != null) {
           // map.getEntry(this),获取到的是这个ThreadLoacl为key最新的Entry
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }
private Entry getEntry(ThreadLocal<?> key) {
            //获取数组里面最大的坐标,就是要去获取最新的Entry
            int i = key.threadLocalHashCode & (table.length - 1);
            Entry e = table[i];
            if (e != null && e.get() == key)
                return e;
            else
                return getEntryAfterMiss(key, i, e);
        }

获取值得过程也是绝对的线程安全的,不可能有别的线程能获取到当前线程的ThreadLocalMap,通过源码发现,他们的值是存在在一个Entry e = table[i];的数组里里面。

三.如何回收ThreadLoacl的

1.通过源码

static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;

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

我们会发现Entry他是继承WeakReference<ThreadLocal<?>>,他是一个弱引用,熟悉JVM的知识,可以知道,弱引用他在每次GC他都会被回收。

四.如何会有value

通过源码:

 private Entry getEntry(ThreadLocal<?> key) {
            int i = key.threadLocalHashCode & (table.length - 1);
            Entry e = table[i];
            if (e != null && e.get() == key)
                return e;
            else
                return getEntryAfterMiss(key, i, e);
        }
 private Entry getEntryAfterMiss(ThreadLocal<?> key, int i, Entry e) {
            Entry[] tab = table;
            int len = tab.length;

            while (e != null) {
                ThreadLocal<?> k = e.get();
                if (k == key)
                    return e;
                if (k == null)
                  //当他发现key->ThrealLocal为空的时候,他就会自动释放了value
                    expungeStaleEntry(i);
                else
                    i = nextIndex(i, len);
                e = tab[i];
            }
            return null;
        }

当他发现key->ThrealLocal为空的时候,他就会自动释放了value

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值