并发编程第13篇,Threadlocal源码解读

tech2023-12-21  74

Threadlocal源码解读

什么是Threadlocal

ThreadLocal提供了线程本地变量,它可以保证访问到的变量属于当前线程,每个线程都保存有一个变量副本,每个线程的变量都不同。ThreadLocal相当于提供了一种线程隔离,将变量与线程相绑定。

Threadloca适用于在多线程的情况下,可以实现传递数据,实现线程隔离。

Threadlocal基本API

  1.New Threadlocal();---创建Threadlocal

  2.set 设置当前线程绑定的局部变量

  3.get  获取当前线程绑定的局部变量

  4.remove()  移除当前线程绑定的变量

Threadlocal简单用法

public class Test003 {     private static ThreadLocal<String> threadLocal = new ThreadLocal<>();     public static void main(String[] args) throws InterruptedException {         Thread thread = new Thread(() -> {             threadLocal.set("哈哈哈哈哈");             System.out.println("成功设置threadLocal");         });         thread.start();         thread.join();         System.out.println(Thread.currentThread().getName() + "," + threadLocal.get());     } }

 

 

根据子线程 在Threadlocal存放局部变量,但是获取的时候是主线程,所以

无法获取。

Threadlocal应用场景

Spring事务模板类获取httprequest

Threadlocal与Synchronized区别

Synchronized与Threadlocal 都可以实现多线程访问,保证线程安全的问题。

Synchronized采用当多个线程竞争到同一个资源的时候,最终只能够有一个线程访问,

采用时间换空间的方式,保证线程安全问题

B.Threadlocal在每个线程中都自己独立的局部变量, 空间换时间,相互之间都是隔离。

相比来说Threadlocal效率比Synchronized效率更高。

 

public class Test004 {     private String context;     public String getContext() {         return threadLocal.get(); //        return context;     }     public void setContext(String context) { //        this.context = context;         threadLocal.set(context);     }     private static Object lock = new Object();     private static ThreadLocal<String> threadLocal = new ThreadLocal<>();     public static void main(String[] args) {         Test004 test004 = new Test004();         for (int i = 0; i < 5; i++) {             int finalI = i;             new Thread(() -> { //                synchronized (lock) {                 test004.setContext(Thread.currentThread().getName() + "," + finalI);                 try {                     Thread.sleep(500);                 } catch (Exception e) {                 }                 System.out.println("线程id:"                         + Thread.currentThread().getName() + "," + test004.getContext()); //                }             }, i + "").start();         }     } }

 

什么是内存溢出

指程序在申请内存时,没有足够的内存空间供其使用,出现 out of memory。 OOM溢出

程序在申请内存时,没有足够的内存空间使用,一般解决办法:加内存。

什么是内存泄漏

指程序在申请内存后,无法释放已申请的内存空间,内存泄露堆积会导致内存被占光,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。

 

强 软 弱 虚引用实现区别

强引用:被引用关联的对象永远不会被垃圾收集器回收

软引用:软引用关联的对象,只有当系统内存溢出时,才会回收软引用的对象。

弱引用:只被弱引用关联的对象,当垃圾回收机制触发的时候就会被回收。

强引用:强引用关联的对象永远是无法被我们垃圾收集器回收。

弱引用:弱引用关联的对象,当垃圾回收机制触发的时候就会被回收。

Object obj = new Object(),这里的的obj就是强引用,通过关键字new创建的对象所关联的引用就是强引用。 只要有强引用指向一个对象,就能表明对象还活着,垃圾收集器就不会触碰这种对象,当JVM内存空间不足,JVM宁愿抛出OutOfMemoryError运行时错误(OOM),使程序异常终止,也不会靠随意回收具有强引用的“存活”对象来解决内存不足的问题。对于一个普通的对象,如果没有其他的引用关系,只要超过了引用的作用域或者显式地将相应(强)引用赋值为 null,就是可以被垃圾收集的了,具体回收时机还是要看垃圾收集策略

public class Test005 {     public static void main(String[] args) {         OrderEntity order1 = new OrderEntity("agsdgs", "hasdx");         // 强引用 //        OrderEntity order2 = order1; //        order1 = null; //        System.out.println(order2); //        System.gc(); //        System.out.println(order2);         // 弱引用         WeakReference<OrderEntity> order2 = new WeakReference<>(order1);         order1 = null;         System.out.println(order2.get());         System.gc();         System.out.println(order2.get());     } }

 

Threadlocal原理分析

 

在每个线程中都有自己独立的ThreadLocalMap对象,中Entry对象。如果当前线程对应的的ThreadLocalMap对象为空的情况下,则创建该ThreadLocalMap

对象,并且赋值键值对。

  Key 为 当前new ThreadLocal对象,value 就是为object变量值。

 

Threadlocal产生内存泄漏问题。

 

因为每个线程中都有自己独立的ThreadLocalMap对象,key为ThreadLocal,value 是为

变量值。

 

Key为ThreadLocal 作为Entry对象的key,是弱引用,当ThreadLocal指向null的时候,

Entry对象中的key变为null,该对象一直无法被垃圾收集机制回收,一直占用到了系统内存,有可能会发生内存泄漏的问题。

 

public class Test006 {     private static ThreadLocal threadLocal = new ThreadLocal<String>();     public static void main(String[] args) {         threadLocal.set("dfr");         threadLocal.remove();         threadLocal = null;         System.gc();         Thread thread = Thread.currentThread();         threadLocal.get();     } }

 

 

如何防御Threadlocal内存泄漏问题

1. 可以自己调用remove方法将不要的数据移除避免内存泄漏的问题,

2. 每次在做set方法的时候会清楚之前 key为null

 

Threadlocal采用弱引用而不是强引用

如果key是为强引用: 当我们现在将ThreadLocal 的引用指向为null,但是

每个线程中有自己独立ThreadLocalMap还一直在继续持有该对象,但是我们

ThreadLocal 对象不会被回收,就会发生ThreadLocal内存泄漏的问题。

 

如果key是为弱引用:

当我们现在将ThreadLocal 的引用指向为null,Entry 中的key指向为null,但是

下次调用set方法的时候,会根据判断如果key空的情况下,直接删除,有可能会发生

Entry 发生内存泄漏的问题。

不管是用强引用还是弱引用都是会发生内存泄漏的问题。

弱引用中不会发生ThreadLocal内存泄漏的问题。

但是最终根本的原因Threadlocal内存泄漏的问题,产生于ThreadLocalMap与

我们当前线程的生命周期一样,如果没有手动的删除的情况下,就有可能会发生内存泄漏的问题。

 

最新回复(0)