线程池、ThreadLocal、Tomcat 应用小结
2016-03-31 19:53
471 查看
这两天遇到几个多线程的问题,多方找资料测试,现记录下测试结果,供自己以后查询用
遇到问题:
项目最近在考虑Rest化,第一个问题就是session管理,现考虑使用redis存储session,并对不需要创建session的接口调用中,使用threadLocal存储用户信息,在请求开始时,将用户信息存储到threadLocal中,第一个问题,user信息会乱掉。
解决过程如下:
1.经调试发现,有时候在设置用户信息之前ThreadLocal中就已经存在了值。
2.然后继续调试,打印出线程号,发现多次请求线程号是相同的,也就是说,N次请求是有可能是使用同一个线程。
3.然后考虑到Tomcat等web容器肯定是有线程池机制的,可能是线程池在搞鬼,查看ThreadLocal源码资料,ThreadLocal最终是绑定在当前的Thread上的,而使用线程池之后,线程执行结束,并不会销毁,而是放回线程池中,这样下次请求时,直接使用了池中的线程,节约线程创建和销毁的资源开销。这样也确实能解释我遇到的问题。
4.当然一切只是猜测,而且自己使用线程池去验证下,代码如下:
创建一个对象,用来测试线程的局部变量:
package com.ych.test; public class TestObj { private int i; public TestObj(int i){ this.i = i; } public void setI(int i) { this.i = i; } public int getI() { return i; } }
创建线程,打印线程中的信息:
public class SaveThread extends Thread{ private TestObj obj; private static ThreadLocal<TestObj> context = new ThreadLocal<TestObj>(); public SaveThread(TestObj obj,String name){ super(name); this.obj = obj; } @Override public void run() { try{ if(context.get() == null){ System.out.println("threadLocal中为null"); }else{ System.out.println("threadLocal中为:"+context.get().getI()); } context.set(obj); System.out.println("thread name is " + Thread.currentThread().getName() + " id为:"+Thread.currentThread().getId()+",变量值:" +obj.getI()); Thread.sleep(2000); }catch(InterruptedException ex){ ex.printStackTrace(); } } }
main方法中执行,查看执行结果:
public class TestThread { private static Executor executor = Executors.newFixedThreadPool(2); public static void main(String[] args) { TestObj t1 = new TestObj(1); TestObj t2 = new TestObj(2); TestObj t3 = new TestObj(3); SaveThread s1 = new SaveThread(t1,"11"); SaveThread s2 = new SaveThread(t2,"22"); SaveThread s3 = new SaveThread(t3,"33"); executor.execute(s1); executor.execute(s2); executor.execute(s3); } }
测试结果:
threadLocal中为null threadLocal中为null thread name is pool-1-thread-2 id为:16,变量值:2 thread name is pool-1-thread-1 id为:15,变量值:1 threadLocal中为:1 thread name is pool-1-thread-1 id为:15,变量值:3
看来我的推测基本是正确的。
最后,解决办法很简单,在spring拦截器中postHandle中remove掉该信息即可。
注:现在还有一个问题困扰我,如果线程不被销毁,那其中的变量岂不是不会被GC回收?如果线程较多的话是否会产生内存泄漏,这个还需要其他方法验证
阅读更多
相关文章推荐
- Tomcat源码分析-线程池应用
- 日常小结-tomcat结构目录、web应用及虚拟目录的映射
- 对tomcat下自制应用服务的性能测试小结
- 一键搞定JavaEE应用,JRE+Tomcat+Mysql-JaveEE绿色运行环境JTM0.9版
- 线程池(领导者-追随者,生产者-消费者等)小结
- tomcat的基本应用
- ThreadLocal(应用场景及使用方式及原理)
- tomcat启动后访问应用超时问题
- 监控Tomcat解决方案(监控应用服务器系列文章)
- Tomcat应用中遇到的几个问题
- Tomcat集群应用部署的实现机制
- 应用CLR的线程池
- struts2.3.4应用开发小结(1)
- Tomcat布署WEB应用两种方式的区别
- java应用 tomcat中实现https安全连接的方法
- java 线程、线程池基本应用示例代码回顾
- 数据库应用小结
- tomcat结合nginx使用小结
- 线程池的应用(缓存的处理思想)
- Android O SYSTEM_UID应用无法使用FileProvider问题小结