此次想总结ThreadLocal这个东西,也是因为项目中使用到了它去帮助保存会话信息。传统的(或者说我在学校的时候)方法,大可能是用服务端的session保存会话,与浏览器端的cookie协做去追踪这个会话。而如今更多的使用ThreadLocal去保存会话的信息,这是因为ThreadLocal天生带有线程安全的特性,而且仅仅在一个线程内共享变量(刚好符合多用户多会话请求这一场景),这就使得这种方式用起来十分顺手和简单。浏览器
1. 项目中的使用:安全
首先记录一下项目中ThreadLocal是如何保存用户会话信息的:cookie
1 private final String KEY_USER = "user"; 2 private final String KEY_TICKET = "ticket"; 3 private final String KEY_ROLEKEY = "roleKey"; 4 5 private static class Inner{ 6 static LocalThreadUtils localThreadUtils = new LocalThreadUtils(); 7 } 8 9 public static LocalThreadUtils getInstance(){ 10 return Inner.localThreadUtils; 11 } 12 13 14 private ThreadLocal<Map<String, Object>> threadLocal = ThreadLocal.withInitial(() -> Maps.newHashMap()); 15 16 17 public void cleanContext(){ 18 threadLocal.get().clear(); 19 }
核心就是这样一个内部类的单例模式,产生的单例有一个theadLocal私有变量,用ThreadLocal修饰,内部是一个Map,而这个map能够由咱们本身去存放用户的各类信息,好比ticket,角色role,用户信息user等。session
ThreadLocal这种方式的优势在于实现简单,并不须要咱们在每一层传递request,也不用考虑httpSession的做用域,咱们能够再任意层(controller,service等)直接访问当前线程信息,从而取出会话信息。spa
2. 实现方式和原理:线程
ThreadLocal类是如何为每一个线程建立一个变量的副本的:code
首先,在每一个线程Thread内部有一个ThreadLocal.ThreadLocalMap类型的成员变量threadLocals,这个threadLocals就是用来存储实际的变量副本的,键值为当前ThreadLocal变量,value为变量副本(即T类型的变量)。对象
初始时,在Thread里面,threadLocals为空,当经过ThreadLocal变量调用get()方法或者set()方法,就会对Thread类中的threadLocals进行初始化,而且以当前ThreadLocal变量为键值,以ThreadLocal要保存的副本变量为value,存到threadLocals。blog
而后在当前线程里面,若是要使用副本变量,就能够经过get方法在threadLocals里面查找。生命周期
其余想要说的:
ThreadLocal真的不是用来解决对象共享访问问题的,而主要是提供了保持对象的方法和避免参数传递的方便的对象访问方式。
一、每一个线程中都有一个本身的ThreadLocalMap类对象,能够将线程本身的对象保持到其中,各管各的,线程能够正确的访问到本身的对象。
二、将一个共用的ThreadLocal静态实例做为key,将不一样对象的引用保存到不一样线程的ThreadLocalMap中,而后在线程生命周期内执行的各处经过这个静态ThreadLocal实例的get()方法取得本身线程保存的那个对象,避免了将这个对象做为参数传递的麻烦。
写在最后:这里只是对ThreadLocal作一个小小的总结,由于在以前的项目中历来没有真正使用过,只是字面上了解他的含义。不少知识确实要经过实践才能有更深入的理解。