ThreadLocal

shuyepl 2023-03-26 11:58:45
Categories: Tags:

MVC三层架构的事务管理

在编写MVC三层架构的Demo时发现,SqlSession的获取是在Dao层的,每一个sql语句的执行都对应着一个SqlSession,而我们在Service层调用Dao层的接口时,由于SqlSession不同就会导致一些事务方面的问题,比如在Service层有几个Dao接口的调用需要开启事务的,但是因为使用了不同的SqlSession导致每个接口调用都是单独的事务,这样就会发生错误,这个时候就需要ThreadLocal来帮忙了,ThreadLocal对象是服务器级别的,一个服务器就一个,我们将当前线程的SqlSession绑定到ThreadLocal中,要使用的时候再从里面取出来,这样就能保证几个Dao接口调用的都是同一个SqlSession对象了。

ThreadLocal是什么

在ThreadLocal中放置的变量可以认为是专属于当前线程的变量,其他线程没有访问到这个变量的可能。

ThreadLocal的作用

ThreadLocal在底层进行数据存储的时候使用的是ThreadLocalMap,一个静态内部类,这个静态内部类创建出的对象为Thread持有,就是说在一个线程中持有ThreadLocalMap类的对象,而这个ThreadLcalMap底层在存储的时候使用了Entry数组,这个数组的key是ThreadLocal对象,而值则是我们设置的。

tips:在使用完ThreadLocal中的值,不需要再次使用的时候,记得调用它的remove()方法,清除一下里面保存的内容,避免内存泄露。(如果是使用在由线程池的地方,不清除这个值也会发生业务方面的问题,如我上面提到的SqlSession,如果不清除的话,从线程池里面取出线程来用,结果SqlSession是前面的事务用的,这不得出错了。)

ThreadLocal内存泄露

现在整理一下思路,Thread对象会持有一个ThreadLocalMap对象,这个对象里面存储了一个Entry数组,这个数组的key是ThreadLocal对象,value是我们自己设置的值,所以,如果ThreadLocal被回收了,那么Entry数组的key就变成null,但是这个时候value并不会被清除,如果不对这个value进行处理的话,就会造成内存泄露。

对value进行清理的方式有两种,一种是上面提到的remove方法,手动清理无用的对象,比较推荐,另外一种是在调用get()、set()、remove()方法的时候会自动清理key为null的对象。


参考资料: