Tomcat 线程池和ThreadLocal的爱恨情仇

这两个对象大家应该都不陌生,一个tomcat响应http请求的线程池,在xml配置文件中可以配置大小,另一个为了保证线程安全用来存储变量的threadlocal对象。这两个如果在使用时配合不好,会给程序引入很大麻烦,并且带来难以fix的bug.

下面以一个工作中的案例为大家讲解,通过报错的日志文件发现创建线程时,提示hashmap转成hashtable失败。

经过查看代码发现一行如下代码

threadlocal<map> a = new threadlocalmap(), 这个threadlocalmap是来自log4j中的一个辅助类继承自threadlocal对象,经过分析发现这个threadlocalmap重写了childvalue方法,立马写到输入参数强转为hashtable,但是这个变量定义的泛型明显是hashmap。因为在程序启动后并无影响,但是在 a 这对象被set值以后如果再次创建线程对象并且在查找childvalue时,就会发生异常。

另外定义的threadlocal对象会一直绑定到tomcat请求的线程里,并且被缓存到线程池内,下次请求再来时如果分配到这个线程上,就会获取到这个绑定的线程对象,你会发现获取到莫名其妙的值。因此,使用threadlocal是为了保证线程安全,在请求线程结束时应该及时清理里面的值。

线程池使用ThreadLocal是为了在多线程环境下,每个线程都能够独立地访问自己的变量副本,而不会受到其他线程的影响。ThreadLocal提供了一种线程局部变量的机制,使得每个线程都可以维护自己的变量副本。 在使用线程池时,我们可以通过在任务执行之前将需要共享的变量设置到ThreadLocal中,然后在任务执行期间获取该变量。这样就可以保证每个线程都能够独立地访问自己的变量副本。 下面是一个使用ThreadLocal的示例代码: ```java import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ThreadPoolExample { private static ThreadLocal<Integer> threadLocal = new ThreadLocal<>(); public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(5); for (int i = 0; i < 10; i++) { final int index = i; executorService.execute(() -> { // 设置线程局部变量的值 threadLocal.set(index); System.out.println("Thread " + Thread.currentThread().getId() + ", value: " + threadLocal.get()); // 清除线程局部变量的值 threadLocal.remove(); }); } executorService.shutdown(); } } ``` 在上述代码中,我们创建了一个固定大小为5的线程池,并通过循环提交了10个任务。在每个任务中,我们将任务的索引存储到ThreadLocal中,并在任务执行期间获取该值并打印出来。最后,我们需要记得在任务执行结束后,清除ThreadLocal中的值,以防止内存泄漏。 通过使用ThreadLocal,每个线程都能够独立地访问自己的变量副本,从而避免了线程安全的问题,并且能够有效地利用线程池来处理多个任务。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值