ThreadLoacl

ThreadLocal

线程局部变量,应用场景多线程。将公共变量复制一份到当前线程中,避免了线程之间使用同一个变量而产生线程安全问题。线程之间的变量是相互隔离的,互不影响,使线程安全运行。

区别

ThreadLocalsynchronized 之间的区别,同样起到使线程安全的作用,两者之间的区别在实现线程安全的方式不一样。

ThreadLocal:将存在线程安全隐患的变量复制一份到当前线程中。线程并发访问,一个线程一份变量。以空间换时间。

synchronized:将存在安全隐患的过程让线程排队执行。线程排队访问,公用一个变量。以时间换空间。

ThreadLocal原理

jdk8以前,由ThreadLocal维护ThreadLocalMap,ThreadLocalMap中Entry的key为Thread,value为此线程绑定的变量。

jdk8以后,由线程Thread维护ThreadLocalMap,ThreadLocalMap中Entry的key为ThreadLocal,value为绑定线程的变量。

以jdk8为例,ThreadLocalMap是作为Thread的成员变量存在

在Thread中定义:

在ThreadLocal中,主要方法set,get,remove都会调用getMap(Thread t)方法获取当前线程的的ThreadLocalMap,对ThreadLocalMap中的Entry进行操作(ThreadLocalMap不是Map

// 获取当前线程的 ThreadLocalMap
ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
}

// 
public void set(T value) {
        Thread t = Thread.currentThread();
        // 获取当前线程的 ThreadLocalMap
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

// 获取当前线程的 ThreadLocalMap
ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

// 当ThreadLocalMap为空时,创建ThreadLocalMap并绑定值
void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

// 
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
            table = new Entry[INITIAL_CAPACITY];
            int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
            table[i] = new Entry(firstKey, firstValue);
            size = 1;
            setThreshold(INITIAL_CAPACITY);
        }


public T get() {
        Thread t = Thread.currentThread();
        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;
            }
        }
        return setInitialValue();
    }

// 移除Entry
public void remove() {
         ThreadLocalMap m = getMap(Thread.currentThread());
         if (m != null)
             m.remove(this);
     }

内存泄漏

当程序中已经动态分配的堆内存,未释放或无法释放时会造成内存的浪费,导致程序运行变慢甚至崩溃。内存泄漏的堆积会造成最终导致内存溢出。

虽然Thread生命周期结束后ThreadLocal也会结束,但现在基本使用线程池的情况下,线程使用完成并不会就此结束,而是回到线程池中等待下次被调用,所以当ThreadLocal使用完后最好调用remove()释放Entry,防止出现内存泄漏。


Spring 自动注入单例或多例的选择

singleton:通过容器获得的总是同一个实例,开销小,当含有有状态的成员变量时,可使用ThreadLocal保证线程的安全性

prototype:每次获取的都是一个新的实例,对CPU、内存的消耗高,线程安全

高并发时使用singleton性能比较好

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值