深入理解线程本地变量ThreadLocal
ThreadLocal理解:
假设在多线程并发环境中。一个可变对象涉及到共享与竞争,那么该可变对象就一定会涉及到线程间同步操作,这是多线程并发问题。
否则该可变对象将作为线程私有对象,可通过ThreadLocal进行管理,实现线程间私有对象隔离的目的。
能够发现,ThreadLocal并没有解决多线程并发的问题,由于ThreadLocal管理的可变对象的性质本来就不会涉及到多线程并发而引发的共享、竞争和同步问题,使用ThreadLocal管理仅仅是方便了多线程获取和使用该私有可变对象的途径和方式。
ThreadLocal解决的问题:
将一个公共的可变对象。转换为线程私有的可变对象,防止出现不对的共享。
《java并发变成实践》
线程本地(ThreadLocal)变量通经常使用于防止在基于可变的单体(Singleton)或全局变量的设计中。出现(不对的)共享。
ThreadLocal的使用场景:
一个可变对象,在每个线程(或者说多线程环境)中都会被使用,而且。该可变对象无需在各个线程间进行同步。那么,该可变对象就能够通过ThreadLocal进行管理。而此时该可变对象变成多实例对象,与线程一一相应。
ThreadLocal主要方法:
public T get() { }返回当前线程所相应的线程局部变量
public void set(T value) { }设置当前线程的线程局部变量的值
public void remove(){} 将当前线程局部变量的值删除,目的是为了降低内存的占用。该方法是JDK 5.0新增的方法。须要指出的是。当线程结束后,相应该线程的局部变量将自己主动被垃圾回收,所以显式调用该方法清除线程的局部变量并非必须的操作。但它能够加快内存回收的速度。
protected T initialValue() { }返回该线程局部变量的初始值,该方法是一个protected的方法。显然是为了让子类覆盖而设计的。这种方法是一个延迟调用方法,在线程第1次调用get()或set(Object)时才运行,而且仅运行1次。
ThreadLocal中的缺省实现直接返回一个null。
ThreadLocal源代码分析:
get方法:
    /**
     * Returns the value in the current thread's copy of this
     * thread-local variable.  If the variable has no value for the
     * current thread, it is first initialized to the value returned
     * by an invocation of the {@link #initialValue} method.
     *
     * @return the current thread's value of this thread-local
     */
    public T get() {
    //获取当前线程对象
        Thread t = Thread.currentThread();
    //从当前线程对象中获取ThreadLocalMap类型实例对象
        ThreadLocalMap map = getMap(t);
        if (map != null) {
        //this对象,也就是ThreadLocal对象作为map的key。获取ThreadLocal管理的可变对象
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
    //map为空,延迟运行初始化方法
        return setInitialValue();
    }
看一下getMap(t)方法:
    /**
     * Get the map associated with a ThreadLocal. Overridden in
     * InheritableThreadLocal.
     *
     * @param  t the current thread
     * @return the map
     */
    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }
补充解释: 
1、ThreadLocalMap,是ThreadLocal的静态内部类 
2、ThreadLocalMap把其外部类ThreadLocal的实例对象作为key,把要管理的可变对象作为value 
3、ThreadLocalMap的实例对象,由当前线程对象Thread的实例持有。而不是由ThreadLocal持有
例如以下图源代码截图进行证明: 
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamF2YWxvdmVpcGhvbmU=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="这里写图片描写叙述" title=""> 
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamF2YWxvdmVpcGhvbmU=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="这里写图片描写叙述" title="">
然后继续看setInitialValue()方法和initialValue()方法:
    /**
     * Variant of set() to establish initialValue. Used instead
     * of set() in case user has overridden the set() method.
     *
     * @return the initial value
     */
    private T setInitialValue() {
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }
    protected T initialValue() {
        return null;
    }
补充说明: 
1、initialValue()方法声明为protected,目的就是让子类覆盖又一次的,假设不覆盖重写。则返回null 
2、假设没有重写initialValue()方法,ThreadLocal对象直接调用get()方法,终于从setInitialValue()返回的对象为null
看一下createMap(t, value)方法:
    /**
     * Create the map associated with a ThreadLocal. Overridden in
     * InheritableThreadLocal.
     *
     * @param t the current thread
     * @param firstValue value for the initial entry of the map
     */
    void createMap(Thread t, T firstValue) {
    //直接new一个新的ThreadLocalMap实例。封装进入当前线程对象t
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }
从上面代码能够发现。每个线程对象都有一个专属自己的ThreadLocalMap对象,而ThreadLocalMap对象存储了ThreadLocal对象与变量对象。线程对象、ThreadLocalMap对象、ThreadLocal对象、变量对象之间的关系例如以下图: 
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamF2YWxvdmVpcGhvbmU=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="这里写图片描写叙述" title="">
最后看一下set(T value)方法:
    /**
     * Sets the current thread's copy of this thread-local variable
     * to the specified value.  Most subclasses will have no need to
     * override this method, relying solely on the {@link #initialValue}
     * method to set the values of thread-locals.
     *
     * @param value the value to be stored in the current thread's copy of
     *        this thread-local.
     */
    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }
补充解释: 
1、set方法用来改动或者初始化ThreadLocal管理的变量对象。
2、ThreadLocal对象调用get方法获取变量的,要么重写initialValue()方法,要么主动调用set方法,否则将返回null。
參考: 
http://blog.csdn.net/lufeng20/article/details/24314381 (此文争议比較大,但依旧能够作为理解ThreadLocal的素材) 
http://www.cnblogs.com/dolphin0520/p/3920407.html 
http://www.iteye.com/topic/103804
深入理解线程本地变量ThreadLocal的更多相关文章
- 线程本地变量ThreadLocal源码解读
		
一.ThreadLocal基础知识 原始线程现状: 按照传统经验,如果某个对象是非线程安全的,在多线程环境下,对对象的访问必须采用synchronized进行线程同步.但是Spring中的各种模板 ...
 - 线程本地变量ThreadLocal
		
一.本地线程变量使用场景 并发应用的一个关键地方就是共享数据.如果你创建一个类对象,实现Runnable接口,然后多个Thread对象使用同样的Runnable对象,全部的线程都共享同样的属性.这意味 ...
 - 线程本地变量ThreadLocal (耗时工具)
		
线程本地变量类 package king; import java.util.ArrayList; import java.util.List; import java.util.Map; impor ...
 - 线程本地变量ThreadLocal (耗时工具)【原】
		
线程本地变量类 package king; import java.util.ArrayList; import java.util.List; import java.util.Map; impor ...
 - JAVA线程本地变量ThreadLocal和私有变量的区别
		
ThreadLocal并不是一个Thread,而是Thread的局部变量,也许把它命名为ThreadLocalVariable更容易让人理解一些. 所以,在Java中编写线程局部变量的代码相对来说要笨 ...
 - Java并发(二十):线程本地变量ThreadLocal
		
ThreadLocal是一个本地线程副本变量工具类. 主要用于将私有线程和该线程存放的副本对象做一个映射,各个线程之间的变量互不干扰,在高并发场景下,可以实现无状态的调用,特别适用于各个线程依赖不同的 ...
 - Threadlocal线程本地变量理解
		
转载:https://www.cnblogs.com/chengxiao/p/6152824.html 总结: 作用:ThreadLocal 线程本地变量,可用于分布式项目的日志追踪 用法:在切面中生 ...
 - 深入理解java:2.4. 线程本地变量 java.lang.ThreadLocal类
		
ThreadLocal,很多人都叫它做线程本地变量,也有些地方叫做线程本地存储,其实意思差不多. 可能很多朋友都知道ThreadLocal为变量在每个线程中都创建了一个副本,那样每个线程可以访问自己内 ...
 - 通过transmittable-thread-local源码理解线程池线程本地变量传递的原理
		
前提 最近一两个月花了很大的功夫做UCloud服务和中间件迁移到阿里云的工作,没什么空闲时间撸文.想起很早之前写过ThreadLocal的源码分析相关文章,里面提到了ThreadLocal存在一个不能 ...
 
随机推荐
- JSONArray和JSONObject的简单使用
			
一.为什么要使用JSONArray和JSONObject 1.后台 -->前台 能够把java对象和集合转化成json字符串格式,这样在前台的ajax方法中能够直接转化成json对象使用 ,从后 ...
 - UI_搭建MVC
			
新建RootViewController 继承于 UIViewController 新建RootView 继承于 UIView AppDelegate.m 中引入 #import "Root ...
 - CF 246 div2 D Prefixes and Suffixes (全部前缀的出现次数)
			
题目链接:http://codeforces.com/contest/432/problem/D 题意:对一个长度不超过10^5的字符串.按长度输出和后缀全然匹配的的前缀的长度,及该前缀在整个串中出现 ...
 - vue1
			
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
 - amaze ui使用简介
			
amaze ui使用简介 amaze UI 类似于bootstrap 不过比bootstrap更加轻量级 可以用来开发响应式网站,并且是移动优先的,针对移动设备开发的网站可以考虑使用这个框架 css中 ...
 - 小项目: low版本的 员工信息程序:
			
### 附加两个文件1 user_info 和worker_info flag = False def logon(): #登录函数 global flag usr = input('Username ...
 - 细说 iOS 消息推送
			
APNS的推送机制 与Android上我们自己实现的推送服务不一样,Apple对设备的控制很严格.消息推送的流程必需要经过APNs: 这里 Provider 是指某个应用的Developer,当然假设 ...
 - mahout算法库(四)
			
mahout算法库 分为三大块 1.聚类算法 2.协同过滤算法(一般用于推荐) 协同过滤算法也可以称为推荐算法!!! 3.分类算法 算法类 算法名 中文名 分类算法 Log ...
 - Day3晚笔记
			
DEV C++扩展栈空间 -Wl,--stack=64000000000 带权二分图匹配 建一个超级源点S,超级汇点T 把左边的点的点权作为权值,连一条S到左边的点的边 把右边的点的点权作为权值,连一 ...
 - POJ 1118 Lining Up 直线穿过最多的点数
			
http://poj.org/problem?id=1118 直接枚举O(n^3) 1500ms能过...数据太水了...这个代码就不贴了... 斜率排序O(n^2logn)是更好的做法...枚举斜率 ...