34 thread

作者: 滔滔逐浪 | 来源:发表于2020-08-05 08:42 被阅读0次

Thread真实应用场景:
1,spring 模板方法
2,spring 编程事务注解
3,aop
4,根据当前线程获取Request 对象
Threadlocal 与Synchronized
1,共同特征: 都可以解决线程安全问题
2,Threadlocal占内存,synchronized不是很占内存
synchronized当多个线程在同时共享到同一个全局变量的时候,只有一个线程对该变量做修改操作,效率非常低,以时间换空间。
Threadlocal 每个线程有独立的缓存局部变量,

package com.taotao.threads.days08;

/**
 *@author tom
 *Date  2020/8/1 0001 8:36
 *
 */
public class Test002 {
    // private String context;

    public String getContext() {
        return threadLocal.get();
    }

    public void setContext(String context) {
        threadLocal.set(context);

    }

    private static ThreadLocal<String> threadLocal = new ThreadLocal<>();

    private static Object lock = new Object();

    public static void main(String[] args) {
        Test002 test002 = new Test002();
        for (int i = 0; i < 500; i++) {
            int finalI = i;
            new Thread(() -> {
                // synchronized (lock){

                threadLocal.set(Thread.currentThread().getName() + "," + finalI);
                // test002.context=Thread.currentThread().getName()+","+ finalI;
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(threadLocal.get());
                //}
            }, i + "").start();
        }
    }
}

什么是内存溢出:
程序在申请内存前的时候。没有足够的内存提供,抛出一个异常oom,加内存
什么是内存泄露:
程序申请内存后,内存无法被垃圾回收机制回收,永远无法释放该内存,造成系统内存的浪费。
1,导致系统卡
2,有可能申请内存的时候出现内存溢出

强引用,弱引用:
强引用: 被引用关联的对象永远不会被垃圾回收机制回收:


package com.taotao.threads.days08;

/**
 *@author tom
 *Date  2020/8/2 0002 9:36
 *强引用
 */
public class Test003 {
    public static void main(String[] args) {
        OrderEntity o1=new OrderEntity(11,"333");
            OrderEntity o2=o1;
        System.out.println(o2);
        o1=null;
        System.gc();
        System.out.println(o2);

    }
}

package com.taotao.threads.days08;

/**
 *@author tom
 *Date  2020/8/2 0002 9:36
 *
 */
public class OrderEntity {
    private int orderId;
    private  String orderName;

    public OrderEntity(int orderId, String orderName) {
        this.orderId = orderId;
        this.orderName = orderName;
    }

    public int getOrderId() {
        return orderId;
    }

    public OrderEntity setOrderId(int orderId) {
        this.orderId = orderId;
        return this;
    }

    public String getOrderName() {
        return orderName;
    }

    public OrderEntity setOrderName(String orderName) {
        this.orderName = orderName;
        return this;
    }
}

弱引用: 只要被弱引用关联的对象,都会被垃圾回收触发回收机制:

package com.taotao.threads.days08;

import java.lang.ref.WeakReference;

/**
 *@author tom
 *Date  2020/8/2 0002 9:45
 *软引用:
 */
public class Test004 {
    public static void main(String[] args) {
        OrderEntity o1=new OrderEntity(2,"3");
        WeakReference<OrderEntity> o2=new WeakReference<>(o1);
                o1=null;
        System.out.println(o2.get());
        System.gc();
        System.out.println(o2.get());

    }
}
 

Thread底层如何实现?
误区: 不是使用大Map 集合实现
ThreadLocalMap:

1,每个线程里有自己独立的ThreadMap 缓存局部变量

    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);
    }



image.png

重点: ThreadLocalMap 设置的key为threadlocal

ThreadLocalMap 底层基于Entry 实现包装。Entry的key 采用弱引用方式指向threadlocal.

分析为什么hi发生内存泄露的问题:
内存泄露的概念: 申请内存后,无法被垃圾回收机制回收,一直占用我们的内存空间,有可能会发生内存泄露问题。
private Entry[] tables;
如果采用弱引用的情况下,现在将threadlocal指向的地址改为null;
当触发gc的时候会从堆内存中移除threadLocal,但是我们的Entry的key指向为null。
但是垃圾回收机制一直无法回收,一直占用内存,所以会发生内存泄露问题。

1,

如何避免内存泄露问题
当我们修改了ThreadLocal指向为null的时候,应该从Entry中移除。
1,直接调用remove方法。
2,使用java反射 机制获取当前线程对应的ThreadLocalMap
手动移除。
3,下次调用set方法的时候,检测链表zhongkey 如果存在、key为空的情况下直接移除。

package com.taotao.threads;

/**
 *@author tom
 *Date  2020/8/3 0003 6:59
 *
 */
public class Test005 {
    private static ThreadLocal<String> threadLocalMap = new ThreadLocal<String>();

    public static void main(String[] args) {
        threadLocalMap.set("99");
        threadLocalMap.remove();;
        threadLocalMap=null;
        System.gc();
        Thread thread=Thread.currentThread();

        threadLocalMap.get();
    }
}


为什么线程中ThreadLocalMap底层数组Entry实现
Entry key=new ThreadLocal();

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

如果key是为强引用: 当我们现在将ThreadLocal 的引用指向为null,但是
每个线程中有自己独立ThreadLocalMap还一直在继续持有该对象,但是我们
ThreadLocal 对象不会被回收,就会发生ThreadLocal内存泄漏的问题。

如果key是为弱引用:
当我们现在将ThreadLocal 的引用指向为null,Entry 中的key指向为null,但是
下次调用set方法的时候,会根据判断如果key空的情况下,直接删除,有可能会发生
Entry 发生内存泄漏的问题。

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

但是最终根本的原因Threadlocal内存泄漏的问题,产生于ThreadLocalMap与
我们当前线程的生命周期一样,如果没有手动的删除的情况下,就有可能会发生内存泄漏的问题。

相关文章

网友评论

      本文标题:34 thread

      本文链接:https://www.haomeiwen.com/subject/jhcprktx.html