ThreadLocal源码解析与运用(下)

ThreadLocal在框架中的运用

ThreadLocal在JAVA框架中得到了大量的运用,甚至上升为一种设计模式,这里随便举几个例子:

  • Struts2中Action的管理
  • Spring中数据库模板Connection的管理
  • Hibernate中Session的管理
  • MyBatis中SQLSession的管理

具体代码可以通过查看源码,或者搜索引擎查找,此处不再赘述。

ThreadLocal在实战中的运用

ThreadLocal在笔者当前的项目中,用于封装MyBatis的分页操作,基本流程就是拦截需要分页的请求,初始化ThreadLocal容器,然后在分页插件中将页数信息存储到容器中,返回结果后再清理容器。
不过在实践中,发现了一个有趣的问题:

SpringMVC 3.2以后添加了异步请求功能,在异步Controller中使用分页上下文时,将无法获取ThreadLocal容器;原因很简单,主线程A进来后,被拦截并初始化ThreadLocal容器,然后异步Controller将会开启多个子线程;接下来在分页拦截器中,想要获取ThreadLocal,将无法获取,因为子线程并不享有父线程的ThreadLocal变量,因而就只能得到空指针异常了。
这个问题的解决方法也挺简单的,使用InheritableThreadLocal来替换ThreadLocal即可。

InheritableThreadLocal

“InheritableThreadLocal”这个单词其实已经在上篇文章 中出现过了,就是Thread源码里的inheritableThreadLocals变量。
相对于ThreadLocal,InheritableThreadLocal的线程安全性稍差。创建一个线程时如果保存了所有 InheritableThreadLocal 对象的值,那么这些值也将自动传递给子线程。如果一个子线程调用 InheritableThreadLocal 的 get() ,那么它将与它的父线程看到同一个对象。为保护线程安全性,应该只对不可变对象(一旦创建,其状态就永远不会被改变的对象)使用 InheritableThreadLocal ,因为对象被多个线程共享。 InheritableThreadLocal 很合适用于把数据从父线程传到子线程,例如用户标识(user id)或事务标识(transaction id),但不能是有状态对象,例如 JDBC Connection 。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容