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的更多相关文章

  1. 线程本地变量ThreadLocal源码解读

      一.ThreadLocal基础知识 原始线程现状: 按照传统经验,如果某个对象是非线程安全的,在多线程环境下,对对象的访问必须采用synchronized进行线程同步.但是Spring中的各种模板 ...

  2. 线程本地变量ThreadLocal

    一.本地线程变量使用场景 并发应用的一个关键地方就是共享数据.如果你创建一个类对象,实现Runnable接口,然后多个Thread对象使用同样的Runnable对象,全部的线程都共享同样的属性.这意味 ...

  3. 线程本地变量ThreadLocal (耗时工具)

    线程本地变量类 package king; import java.util.ArrayList; import java.util.List; import java.util.Map; impor ...

  4. 线程本地变量ThreadLocal (耗时工具)【原】

    线程本地变量类 package king; import java.util.ArrayList; import java.util.List; import java.util.Map; impor ...

  5. JAVA线程本地变量ThreadLocal和私有变量的区别

    ThreadLocal并不是一个Thread,而是Thread的局部变量,也许把它命名为ThreadLocalVariable更容易让人理解一些. 所以,在Java中编写线程局部变量的代码相对来说要笨 ...

  6. Java并发(二十):线程本地变量ThreadLocal

    ThreadLocal是一个本地线程副本变量工具类. 主要用于将私有线程和该线程存放的副本对象做一个映射,各个线程之间的变量互不干扰,在高并发场景下,可以实现无状态的调用,特别适用于各个线程依赖不同的 ...

  7. Threadlocal线程本地变量理解

    转载:https://www.cnblogs.com/chengxiao/p/6152824.html 总结: 作用:ThreadLocal 线程本地变量,可用于分布式项目的日志追踪 用法:在切面中生 ...

  8. 深入理解java:2.4. 线程本地变量 java.lang.ThreadLocal类

    ThreadLocal,很多人都叫它做线程本地变量,也有些地方叫做线程本地存储,其实意思差不多. 可能很多朋友都知道ThreadLocal为变量在每个线程中都创建了一个副本,那样每个线程可以访问自己内 ...

  9. 通过transmittable-thread-local源码理解线程池线程本地变量传递的原理

    前提 最近一两个月花了很大的功夫做UCloud服务和中间件迁移到阿里云的工作,没什么空闲时间撸文.想起很早之前写过ThreadLocal的源码分析相关文章,里面提到了ThreadLocal存在一个不能 ...

随机推荐

  1. 云计算时代告别phpMyAdmin

    云计算时代告别phpMyAdmin phpMyAdmin是一款很经典的MySQL数据库管理工具,在云计算快速发展的今天,phpMyAdmin交互老旧.已经不能适应时代步伐.因此有很多人開始选择一些更高 ...

  2. Python!Are you kidding me?

    前几天由于python给我带来了兴奋写了一篇文章叫做<The beauty of python 1>,今天则是由于一个小错误而写下此文. 也是缘因为我的工作,问题是这种: 我有一个文档.里 ...

  3. Reuse Is About People and Education, Not Just Architecture

     Reuse Is About People and Education, Not Just Architecture Jeremy Meyer you MigHT AdopT THE AppRoA ...

  4. OpenCASCADE 麻花钻头造型实例分析

    OpenCASCADE 麻花钻头造型实例分析 eryar@163.com Abstract. OpenCASCADE provides a simple twist drill bit modelin ...

  5. Image-Loader LruMemoryCache

    这段时间在研究Universal-Image-Loader 这个图片处理开源框架,这里主要分析一下它的LRU(Least Resently Used,最近最少使用算法)内存缓存的实现. 在UIL它提供 ...

  6. js---06函数传参数

    <!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" content ...

  7. 关于li的排列,我的面试题

    来到北京的第二周,收到了单位的面试,一面的时候面试官问了微信钱包里的那个快速入口的排列,我当时在面试官的引导下答的还可以,但是在实际中有很多的方法和各自不同的问题,我来总结下. 1.flex布局,其实 ...

  8. android webview 报 [ERROR:in_process_view_renderer.cc(189)] Failed to request GL process. Deadlock likely: 0 问题

    工作中遇到 使用webview中加载含有audio标签的页面时提示[ERROR:in_process_view_renderer.cc(189)] Failed to request GL proce ...

  9. js 判断是不是空、值是否存在

    判断数组是否存在某个值: Array.indexOf(val) > -1 //存在 (缺陷:一是不够语义化,它的含义是找到参数值的第一个出现位置,所以要去比较是否不等于-1,表达起来不够直观.二 ...

  10. 求s=a+aa+aaa+aaaa+aa...a的值,其中a是一个数字。 例如2+22+222+2222+22222(此时共有5个数相加),几个数相加有键盘控制。

    代码: package com.liron.p1; import java.io.IOException; import java.util.Scanner; /** * 求s=a+aa+aaa+aa ...