深入学习ThreadLocal
1、用来干吗的?
用于线程在任意的地方去共享数据,而不被其他线程所干扰,
2、原理是什么
因为每个线程维护一份ThreadLocalMap,使用threadlocal.set(obj)方法是存放在map里面的Entry<<WeekReference>ThreadLocal,Value>数组里
3、实际案例,比如写了util类,但是SimplateDateFormate是线程不安全的,定义成成员变量多线程调用就会有问题,使用threadlocal相当于每个线程都有一份这个value,也就是simplateDateFormate对象
4、为什么不使用thread的id作为Entry的key
当有两个ThreaLocal1和ThreadLocal2时候,在local1设置的值会被loca2中读到,但使用Threadlocal作为key就能区分
5、key为什么会设置弱引用,为什么会内存泄漏
当手动回收了ThreadLocal对象,如果是强引用,那么Entry还有一个对ThreadLocal的强引用,如果不手动删除,会导致这个Entry一直存在
从而导致内存泄漏,当使用弱引用,回收了ThreadLocal对象后,Entry里面是个弱引用,ThreadLocal就会被回收,Entry面的key变成null
在下一次get set remove就会清除掉这些key为null的数据 ,相当于提供了一层保障。
6、使用注意点
使用static修饰threadlocal修饰,当get完调用一次remove清除当此的Entry.
附上一个线程泄漏导致oom的例子
VM参数 -Xms5m -Xmx5m -XX:+HeapDumpOnOutOfMemoryError
package com.xiangwen.day10; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class ThreadLocalTest2 { private static ThreadLocal<MyThreadLocal> threadLocal = new ThreadLocal<>(); public static void main(String[] args) { ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 0, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1000)); for (int i = 0; i < 10; i++) { executor.execute(new Runnable() { @Override public void run() { long time= Math.round(Math.random()*2000); try { Thread.sleep(time); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println(Thread.currentThread().getName() + "休眠结束"+time); MyThreadLocal myThreadLocal = new MyThreadLocal(); threadLocal.set(myThreadLocal); // System.gc(); //threadLocal.remove(); } }); } } static class MyThreadLocal { private byte[] bytes = new byte[1 * 1024 * 1024]; } }