解决并发问题最简单的方案就是减少共享,JAVA提供了一个简单的工具类即ThreadLocal,我们会用他来保存线程之间独立存在的变量,比如springmvc中,我们每个请求特有的一些属性。
ThreadLocal的设计
在设计上JAVA的Thread内部类会持有一个ThreadLocalMap的对象threadLocals,Map的结构(ThreadLocal,Value),其中ThreadLocal是弱引用。
这么做的设计有俩点:
- 因为ThreadLocal对象和线程的声明周期息息相关,从数据的亲原性来讲,由Thread对象管理更为合适
- 防止内存泄露,因为ThreadLocal内部持有线程和Value的对应关系,当线程声明结束后,ThreadLocal中的Thread对象不会主动释放。从而造成内存泄露
ThreadLocal的内存泄露
在线程池中,Thread的生命周期往往很长,而因为ThreadLocalMap对于ThreadLocal是软引用,所以当ThreadLocal没有引用时候会被释放掉,但是Value确是强引用,所以会造成ThreadLocal释放掉了,但是Value没法释放导致内存泄露
解决方法:手动释放
InheritableThreadLocal继承性
因为ThreadLocal是线程不共享的,所以如果线程在创建一个子线程是看不到主线程ThreadLocal对象的值的,为了让子线程能看到父类线程提供InheritableThreadLocal,但是不建议使用,因为往往会导致子线程修改了值引起主线程的逻辑混乱。