1、目录
2、ThreadLocal是什么?有什么用?
/** * 回顾synchronized在多线程共享线程的问题 * @author qiuyongAaron */ public class ThreadLocalOne { volatile Person person=new Person(); public synchronized String setAndGet(String name){ //System.out.print(Thread.currentThread().getName()+":"); person.name=name; //模拟网络延迟 try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } return person.name; } public static void main(String[] args) { ThreadLocalOne threadLocal=new ThreadLocalOne(); new Thread(()->System.out.println(threadLocal.setAndGet("arron")),"t1").start(); new Thread(()->System.out.println(threadLocal.setAndGet("tony")),"t2").start(); } } class Person{ String name="tom"; public Person(String name) { this.name=name; } public Person(){} } 运行结果: 无synchronized: t1:tony t2:tony 有synchronized: t1:arron t2:tony
- 无synchronized的时候,由于非原子操做,显然不是预想结果,可参考我关于synchronized的讨论。
- 如今,咱们的需求是:每一个线程独立的设置获取person信息,不被线程打扰。
- 由于,person是共享数据,用同步互斥锁synchronized,当一个线程访问共享数据的时候,其余线程堵塞,再也不多余赘述。
/** * 谈谈ThreadLocal的做用 * @author qiuyongAaron */ public class ThreadLocalThree { ThreadLocal<Person> threadLocal=new ThreadLocal<Person>(); public String setAndGet(String name){ threadLocal.set(new Person(name)); try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } return threadLocal.get().name; } public static void main(String[] args) { ThreadLocalThree threadLocal=new ThreadLocalThree(); new Thread(()->System.out.println("t1:"+threadLocal.setAndGet("arron")),"t1").start(); new Thread(()->System.out.println("t2:"+threadLocal.setAndGet("tony")),"t2").start(); } } 运行结果: t1:arron t2:tony


- ThreadLocal被称为线程局部变量,说白了,他就是线程工做内存的一小块内存,用于存储数据。
- 那么,ThreadLocal.set()、ThreadLocal.get()方法,就至关于把数据存储于线程本地,取也是在本地内存读取。就不会像synchronized须要频繁的修改主内存的数据,再把数据复制到工做内存,也大大提升访问效率。
- 回到最开始的举例,也就等价于mabatis、hibernate为何要使用threadlocal来存储session?
- 做用一:由于线程间的数据交互是经过工做内存与主存的频繁读写完成通讯,然而存储于线程本地内存,提升访问效率,避免线程阻塞形成cpu吞吐率降低。
- 做用二:在多线程中,每个线程都须要维护session,轻易完成对线程独享资源的操做。
3、ThreadLocal源码简要总结?
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); }
- 一个线程对应一个ThreadLocalMap ,能够存储多个ThreadLocal对象。
- ThreadLocal对象做为key、独享数据做为value。
- ThreadLocalMap可参考HashMap,在ThreadMap里面存在Entry数组也就是一个Entry一个键值对。
public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); }
- 一个线程对应一个ThreadLocalMap,get()就是当前线程获取本身的ThreadLocalMap。
- 线程根据使用那一小块的threadlocal,根据ThreadLocal对象做为key,去获取存储于ThreadLocalMap中的值。
4、ThreadLocal为何会致使内存泄漏?
- Key使用强引用:也就是上述说的状况,引用ThreadLocal的对象被回收了,ThreadLocal的引用ThreadLocalMap的Key为强引用并无被回收,若是不手动回收的话,ThreadLocal将不会回收那么将致使内存泄漏。
- Key使用弱引用:引用的ThreadLocal的对象被回收了,ThreadLocal的引用ThreadLocalMap的Key为弱引用,若是内存回收,那么将ThreadLocalMap的Key将会被回收,ThreadLocal也将被回收。value在ThreadLocalMap调用get、set、remove的时候就会被清除。
- 比较两种状况,咱们能够发现:因为
ThreadLocalMap
的生命周期跟Thread
同样长,若是都没有手动删除对应key
,都会致使内存泄漏,可是使用弱引用能够多一层保障:弱引用ThreadLocal
不会内存泄漏,对应的value
在下一次ThreadLocalMap
调用set
,get
,remove
的时候会被清除。