并发编程-Threadlocal

网友投稿 625 2022-10-26

并发编程-Threadlocal

并发编程-Threadlocal

文章目录

​​Threadlocal​​

​​原理解析​​

​​内存关系图​​​​主要方法​​​​内存泄漏原因​​

Threadlocal

threadlocal是一个创建线程局部变量的类

threadlocal创建的变量只能被当前线程访问,其他线程无法访问和修改

原理解析

内存关系图

每个thread内部有一个threadlocalMap

.ThreadLocalMap threadLocals = null;

threadLocalMap内部其实是由entry数组构建的map,每个entry的key是threadlocal本身,value是你要保存的值

static class ThreadLocalMap { static class Entry extends WeakReference> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal k, Object v) { super(k); value = v; } } //...... }

一句话总结就是:Thread维护了ThreadLocalMap,而ThreadLocalMap里维护了Entry,而Entry里存的是以ThreadLocal为key,传入的值为value的键值对。

主要方法

get

public T get() { Thread t = Thread.currentThread(); // 获取当前线程,通过当前线程获取该线程的threadlocalmap ThreadLocalMap map = getMap(t); if (map != null) { // 根据threadlocal实例获取到该map中的指定entry ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") // 取出值 T result = (T)e.value; return result; } } // 如果map为空,则设置默认值 return setInitialValue(); } private T setInitialValue() { T value = initialValue();// null Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) // 默认:this,null map.set(this, value); else // 如果连map都没初始化,则构造map createMap(t, value); return value; } protected T initialValue() { return null; } void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); }

set

public void set(T value) { // 获取到当前线程的threadlocalmap Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) // map不为空则设置值 map.set(this, value); else // 为空则构造map createMap(t, value); }

remove,每次使用完threadlocal的value后手动remove也是防止内存泄露的最佳手段。

public void remove() { // 根据当前threadlocal实例移除指定entry ThreadLocalMap m = getMap(Thread.currentThread()); if (m != null) m.remove(this); }

为什么会出现内存泄漏?

内存泄漏原因

原因在于threadlocal的entry的key是弱引用,value是强引用

static class Entry extends WeakReference> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal k, Object v) { super(k); value = v; } }

知识补充:四大引用

强引用:平时new对象:Object o = new Object()出来的引用就是强引用,强引用不管内存足不足够,都不会被GC回收软引用:继承SoftReference类实现的对象就是软引用,软引用在内存足够时不会被GC回收,内存不足时才会被GC弱引用:继承WeakReference类实现的对象就是弱引用,只要GC,就会被回收虚引用:PhantomReference,在任何时候都可能被垃圾回收。 虚引用主要用来跟踪对象被垃圾回收的活动

所以,因为key是弱引用,所以只要GC就会被回收,value是强引用,如果key被回收了,value没有被回收,那么这个value是永远不能被用到,如果类似的value越来越多,就会产生OOM

ThreadLocal一定线程安全?

未必,如果在每个线程中ThreadLocal.set()进去的东西本来就是多线程共享的同一个对象,比如static对象,那么多个线程的ThreadLocal.get()获取的还是这个共享对象本身,还是有并发访问线程不安全问题。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:rabbitmq学习系列教程之消息应答(autoAck)、队列持久化(durable)及消息持久化
下一篇:Gondola - Web框架用于编写更快的网站
相关文章

 发表评论

暂时没有评论,来抢沙发吧~