ThreadLocal研究

我在hibernate工厂类中看到了关于ThreadLocal的使用,threadLocal显然是类变量,全局的
是否这样表示不同的线程共享了threadLocal,事实上没错,多个线程取得到是同一样threadLocal
但是在不同的线程中使用threadLocal得到的变量不一样。那么什么是同一线程呢,我们可以这样理解
线程是主线程创建分支线程调用类执行完再返回主线程,那么这么这分支线程上所执行的所有对象的
方法实际上是同一个线程,除非中间使用多线程方法去创建其它分支线程。因此从创建分支线程
开始的那个方法一直执行到返回都是在同一线程中,其中引用的类,对象,方法都属性同一线程。

显示当前线程的方法为:
System.out.println(Thread.currentThread());

那么线程和对象方法有什么关系呢。当创建线程分支时,很显然就决定一个程序执行的线,
这个线的入口就是创建线程时给的方法的入口,方法一直向下执行,一部部的调用引用的其它类中的方法
如果碰到了实例化就加载类,如果类已加载过就直接实例化,如果static,在加载时就实际上分配了地址
直接跳到引用的地址继续执行,一直到执行完后返最后的代码。

在测试的过程中发现我们请求不同的页面时调用threadLocal.get()的结果一样的,这就有点奇怪了,
我测试的服务器是tomcat6.0+JDK1.6,为了模拟并发,我在其中一个线程中使用Thread.sleep(10000)
让线程等待10秒钟,结果发现再去请求另一个页面执行的线程并不一样,但是发现后面一个请求用的是前面
用过的一个线程,因此从这个线程得到的get()和前面执行完的那个线程一样的,只是和等待的那个线
程不一样。

因此有如下结论:
1)web请求的时分配的线程可能是以前用过的一个旧线程,线程保存着原来的一些值。
2)当并发产生时,会分配新的线程,新的线程和同时发生的别一个线程不是同一个线程,但是都有可能是以前的旧线程。
3)tomcat用的是线程池,有点类似于数据的连接池。
4)因此我们用完一个threadLocal应对其进行清除,以免下一个请求得到旧数据而产生影响。


在研究测试中发现。
1)Thread中有一个属性为:ThreadLocal.ThreadLocalMap threadLocals = null;
   也就是每一个线程都有这么一个ThreadLocalMap,这是线程所有固有的。当然如果没有使用到,这只是一个空属性。
  
2)而ThreadLoacl中的方法创建了一个ThreadLocal.ThreadLocalMap实例,相当于
   threadLocals = new ThreadLocalMap();
  
3)因此每一个线程都有一个ThreadLocalMap,只是没有使用时是空的罢了。

public T get()
  {
    Thread localThread = Thread.currentThread();
    ThreadLocalMap localThreadLocalMap = getMap(localThread);
    if (localThreadLocalMap != null)
      return ThreadLocalMap.access$000(localThreadLocalMap, this);
    Object localObject = initialValue();
    createMap(localThread, localObject);
    return localObject;
  }
 
public void set(T paramT)
  {
    Thread localThread = Thread.currentThread();
    ThreadLocalMap localThreadLocalMap = getMap(localThread);
    if (localThreadLocalMap != null)
      ThreadLocalMap.access$100(localThreadLocalMap, this, paramT);
    else
      createMap(localThread, paramT);
  }
 
   ThreadLocalMap getMap(Thread paramThread)
  {
    return paramThread.threadLocals;
  }
4)从上面ThreadLoacl原码可知getMap实际上就是得到指定线程的threadLocals值,当然threadLocals可能为null,而threadLocals就是一个ThreadLocal.ThreadLocalMap
5)我们看到上面的set方法也是一样的,调用了getMap方法。
6)Thread中的threadLocals 虽然没有说明作用域,但测试发现是protected类型,只有在子类或者同一个包中才能引用到。
因此我们只能通过和Thread的同一个包中的类来引用它。
 

------------------------------------------------------------------------------------
private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
/**
* 得到session,此sessiond存有全属对象.
* @return //Session
*/
public static Session getSession()
{
Session re = threadLocal.get(); //这个地方不同的线程得到的值不一样的。
if(re==null) //此方法看线程变量中是否有值,如果有就用现存的值,没有就新实例化一个。
{
re = new Session();
threadLocal.set(re);
}
return re;
}

--------------------------------------------------------------
测试:1)看是否protected在同一个包中是否可引用。
测试结果:可以引用。

总结:private 只有在类内访问,就算是内部类也不能访问。
protected 类内,子类,同一个包中的类可以访问。
public 只要指明在那个包中,任何其它类都可能访问。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值