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与
我们当前线程的生命周期一样,如果没有手动的删除的情况下,就有可能会发生内存泄漏的问题。
网友评论