Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1663043
  • 博文数量: 695
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 4027
  • 用 户 组: 普通用户
  • 注册时间: 2013-11-20 21:22
文章分类

全部博文(695)

文章存档

2018年(18)

2017年(74)

2016年(170)

2015年(102)

2014年(276)

2013年(55)

分类: Java

2017-11-03 14:56:41

面试过程中遇到一个问题,web项目中Controller和Service层之间怎么传递数据(除了使用参数传递)
当时首先想到ThreadLocal,但是没说出来,以后面试中想到什么就尽量说出来不要怕说错
但是没有对ThreadLocal做深入了解所以接下来的问题也是一问三不知
主线程新起线程后,两个线程之间的ThreadlLocal之间的关系?
其实没有关系,就是想让你说出来 新线程中ThreadLocal是对主线程的复制,之后主线程中在对ThreadLocal修改,不会影响新起线程中的内容
关于具体实现
每个Thread对象中,都有一个ThreadLocalMap类型的对象,该map是以本线程中的ThrealLoacl对象为key,以ThreadLoacl的值为value
Thread对象中的ThreadLocalMap默认是null。所以使用get前必须先set,如果不set的话就得重写initialValue方法。

点击(此处)折叠或打开

  1. public class SequenceB implements Sequence {
  2.     //private static ThreadLocal num = new ThreadLocal();
  3.     private static ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>() {
  4.         public Integer initialValue() {
  5.             return 0;
  6.         }
  7.     };
  8.     @Override
  9.     public int getNum() {
  10.         // TODO Auto-generated method stub
  11.         seqNum.set(seqNum.get()+1);
  12.         return seqNum.get();
  13.     }
  14.     public static void main(String []args){
  15.         SequenceB sb = new SequenceB();
  16.         new Thread(new ClientThread(sb),"thread1").start();
  17.         new Thread(new ClientThread(sb),"thread2").start();
  18.         new Thread(new ClientThread(sb),"thread3").start();
  19.     }

  20. }
get()方法是用来获取ThreadLocal在当前线程中保存的变量副本,set()用来设置当前线程中变量的副本,remove()用来移除当前线程中变量的副本,initialValue()是一个protected方法,一般是用来在使用时进行重写的,它是一个延迟加载方法,下面会详细说明。

  首先我们来看一下ThreadLocal类是如何为每个线程创建一个变量的副本的。

  先看下get方法的实现:


第一句是取得当前线程,然后通过getMap(t)方法获取到一个map,map的类型为ThreadLocalMap。然后接着下面获取到键值对,注意这里获取键值对传进去的是  this,而不是当前线程t。

  如果获取成功,则返回value值。

  如果map为空,则调用setInitialValue方法返回value。

  我们上面的每一句来仔细分析:

  首先看一下getMap方法中做了什么:


可能大家没有想到的是,在getMap中,是调用当期线程t,返回当前线程t中的一个成员变量threadLocals。

  那么我们继续取Thread类中取看一下成员变量threadLocals是什么:
********************************

******************************

实际上就是一个ThreadLocalMap,这个类型是ThreadLocal类的一个内部类,我们继续取看ThreadLocalMap的实现:



可以看到ThreadLocalMap的Entry继承了WeakReference,并且使用ThreadLocal作为键值。

  然后再继续看setInitialValue方法的具体实现:




很容易了解,就是如果map不为空,就设置键值对,为空,再创建Map,看一下createMap的实现:


至此,可能大部分朋友已经明白了ThreadLocal是如何为每个线程创建变量的副本的:

  首先,在每个线程Thread内部有一个ThreadLocal.ThreadLocalMap类型的成员变量threadLocals,这个threadLocals就是用来存储实际的变量副本的,键值为当前ThreadLocal变量,value为变量副本(即T类型的变量)。

  初始时,在Thread里面,threadLocals为空,当通过ThreadLocal变量调用get()方法或者set()方法,就会对Thread类中的threadLocals进行初始化,并且以当前ThreadLocal变量为键值,以ThreadLocal要保存的副本变量为value,存到threadLocals。

  然后在当前线程里面,如果要使用副本变量,就可以通过get方法在threadLocals里面查找。


http://www.cnblogs.com/dolphin0520/p/3920407.html
http://www.cnblogs.com/digdeep/p/4510875.html

阅读(673) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~