2025年threadlocal底层实现_什么是底层

threadlocal底层实现_什么是底层ThreadLocal 作用 提供线程内的局部变量 不同的线程之间不会相互干扰 这种变量在线程的生命周期内起作用 减少同一个线程内多个函数或组件之间一些公共变量传递的复杂性 package com mupack public class App private String content public void setContent String

ThreadLocal

作用:
提供线程内的局部变量,不同的线程之间不会相互干扰,这种变量在线程的生命周期内起作用,减少同一个线程内多个函数或组件之间一些公共变量传递的复杂性。

package com.mupack;

public class App
{

private String content;

public void setContent(String content) {

this.content = content;
}
public String getContent() {

return content;
}
public static void main(String[] args) throws Exception {

App app = new App();
for(int i = 0;i < 5; i ++){

Thread thread = new Thread(new Runnable(){


@Override
public void run() {

app.setContent(Thread.currentThread().getName() + "的数据");
System.out.println("--------------------");
System.out.println(Thread.currentThread().getName() + "-------->" + app.getContent());
}
});
thread.setName("线程" + i);
thread.start();
}
}
}

----

换成ThreadLocal后

package com.mupack;

public class App
{

ThreadLocal t1 = new ThreadLocal<>();
public void setContent(String content) {

t1.set(content);
}
public String getContent() {

return t1.get();
}
public static void main(String[] args) throws Exception {

App app = new App();
for(int i = 0;i < 5; i ++){

Thread thread = new Thread(new Runnable(){


@Override
public void run() {

app.setContent(Thread.currentThread().getName() + "的数据");
System.out.println("--------------------");
System.out.println(Thread.currentThread().getName() + "-------->" + app.getContent());
}
});
thread.setName("线程" + i);
thread.start();
}
}
}

----

ThreadLocal典型应用场景
Mapper层需要处理异常以判断事务是否回滚,所有的数据库操作都需要用到一个connection,这个时候可以把connection和当前线程关联起来。

----

强软弱虚引用

----

5. 强引用:最常见的引用

Object o = new Object()

当没有印用指向new Object的时候,new Object()会被垃圾回收器回收

6. 软引用

package com.mupack;

import java.lang.ref.SoftReference;

import jdk.management.resource.internal.inst.ThreadRMHooks;

public class App
{

public static void main(String[] args) throws Exception {

SoftReference softReference = new SoftReference(new byte[1024 * 1024 * 10]);
//有值
System.out.println(softReference.get());
System.gc();
//等一下垃圾回收,这个时候jvm内存充足,不会回收软引用。
try {

Thread.sleep(500);
} catch (Exception e) {

//TODO: handle exception
e.printStackTrace();
}
//有值
System.out.println(softReference.get());
//这时候再定义一个数组,heap将装不下,这时候系统会垃圾回收,先回收一次,如果还不够,则把软引用也回收了。
byte[] b = new byte[1024 * 1024 * 15];
System.out.println(softReference.get());
}
}

软引用实例:
当我们手动把jvm虚拟机内存调成20M,一开始定义一个10M数组,Heap够用,当时当第二次定义一个15M数组的时候,Heap不够用,所以垃圾回收器回收软引用。

3. 弱引用

package com.mupack;

import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;

import jdk.management.resource.internal.inst.ThreadRMHooks;

public class App
{

public static void main(String[] args) throws Exception {

WeakReference m = new WeakReference<>(new M());
//有值
System.out.println(m.get());
System.gc();
//没值
System.out.println(m.get());

}
}

弱引用遭遇到垃圾回收器(gc)就会被回收。

4. 虚引用

当一个虚引用被回收的时候,他会把信息传递到队列中去。虚引用其实并没有引用对象,只是当被回收的时候传递一个消息而已。

package com.mupack;

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.util.List;
import java.util.Queue;

import jdk.management.resource.internal.inst.ThreadRMHooks;

public class App {

static private Queue QUEUE;
static private List LIST;

public static void main(String[] args) throws Exception {

PhantomReference phantomReference = new PhantomReference(new M(), (ReferenceQueue) QUEUE);
new Thread(() -> {

while(true){

LIST.add(new byte[1024 * 1024]);
try {

Thread.sleep(1000);
} catch (Exception e) {

//TODO: handle exception
e.printStackTrace();
Thread.currentThread().interrupt();
}
//一直打印null
System.out.println(phantomReference.get());
}
}).start();


}
}


DirectByteBuffer是JVM内存中的一片内存,用来指向对外内存(操作系统管理的内存),操作系统管理的内存JVM垃圾处理器不能回收,所以当DirectByteBuffer回收后,会在队列中有相应的记录,之后JVM会去处理对外内存。(JVM是C++写的所以能够处理操作系统内存)。

----

各种引用用途:

强引用:最常用的一种引用

软引用:适合做缓存,比如内存中一张图片,当内存不够用的时候先把图片移动出去,当内存充足的时候再把图片load进来

弱引用:为了解决某些地方的内存泄露问题。

虚引用:主要是应用在与系统内存区域交互的时候,比如从网络中下载的数据,如果没有虚引用,我们需要先把数据加载到JVM内存才能让JVM管理,现在有了虚引用,直接用JVM中的DirectByteBuffer内存区域指向系统内存,当DirectByteBuffer回收后,会通知队列,这时候JVM垃圾回收器就知道去系统内存请理相应的系统内存空间

----

ThreadLocal底层:

每个ThreadLocal对应一个ThreadLocalMap(ThreadLocal内部类),每一个ThreadLocal中存储多个Entry,每个Entry的key为ThreadLocal对象,value为响应的值

public Class Thread{ 

...
ThreadLocal.ThreadLocalMap threadLocals = null;
...
}

1. get()方法

public T get() { 

//获取当前线程
Thread t = Thread.currentThread();
//获取Thread中的Map
ThreadLocalMap map = getMap(t);
if (map != null) {

//获取Entry
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {

@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
//当Thread中没有ThreadLocalMap或者ThreadLocalMap中找不到响应的key时执行初始化
return setInitialValue();
}

2. initialValue()方法

private T setInitialValue() { 

//获取一个初始值,默认为null
T value = initialValue();
//获取当前线程
Thread t = Thread.currentThread();
//获取当前线程的Map
ThreadLocalMap map = getMap(t);
if (map != null)
//如果Map存在,则设置
map.set(this, value);
else
//如果Map不存在,则创建一个Map,并且赋值
createMap(t, value);
return value;
}

3. set()方法

    public void set(T value) { 

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

4. remove()方法

public void remove() { 

//获取当前线程的Map
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
//移除Map中的key,value
m.remove(this);
}

ThreadLocal中的内存泄露问题

Entry对象实际是一个弱引用,如果一个对象只有弱引用的时候,那当垃圾回收器遇见他的时候它就会被回收。

//Entry继承弱引用类
static class Entry extends WeakReference> {

/** The value associated with this ThreadLocal. */
Object value;

Entry(ThreadLocal k, Object v) {

//调用父接口,令弱引用指向ThreadLocal变量
super(k);
value = v;
}
}


若是强引用,当tl = null之后,Thread线程对象还是会一直存在,这时会形成一个引用链(Thread->ThreadLocalMap->Entry->ThreadLocal),导致ThreadLocal仍然释放不了,所以ThreadLocal应该使用弱引用,当tl = null后垃圾回收器一遇见ThreadLocal就直接回收掉ThreadLocal。但是这样仍然会存在内存泄漏问题,即ThreadLocal被回收之后,key不存在,导致value无法被访问到,所以正确的用法应该是不用ThreadLocal的时候手动remove掉。

编程小号
上一篇 2025-03-31 19:30
下一篇 2025-03-21 22:17

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/hz/110682.html