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

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应用场景

  1. Spring事务模板类
  2. 获取httprequest

Threadlocal与Synchronized区别

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

  1. 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原理分析

 

  1. 在每个线程中都有自己独立的ThreadLocalMap对象,中Entry对象。
  2. 如果当前线程对应的的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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值