ThreadLocal类提供线程本地变量,为变量在每个线程创建一个副本,每个线程可以访问自己内部的副本变量。

比如,有这样一个需求,需要为每个线程创建一个独一无二的标识,这个标识在第一次调用ThreadId.get()的时候生成,在随后的调用中不会再改变。

public class ThreadId {
private static final AtomicInteger nextId = new AtomicInteger(0); private static final ThreadLocal<Integer> threadId =
new ThreadLocal<Integer>() {
@Override
protected Integer initialValue() {
return nextId.getAndIncrement();
}
};
public static int get() {
return threadId.get();
}
}

类声明:

public class ThreadLocal<T> {}

实例变量和相关的一个方法:

//用于ThreadLocalMap
private final int threadLocalHashCode = nextHashCode(); //下一个hash code,从0开始
private static AtomicInteger nextHashCode = new AtomicInteger(); //hash增量
private static final int HASH_INCREMENT = 0x61c88647; //在获取下一个hash code
private static int nextHashCode() {
return nextHashCode.getAndAdd(HASH_INCREMENT);
}

构造方法:

public ThreadLocal() {}

重要的操作:

//线程本地变量的初始化方法,访问修饰符为protected是为了让程序员可以覆盖这个方法,默认是返回null,也就是说默认的线程本地变量值为null
protected T initialValue() {
return null;
}

get操作

//获取当前线程的本地变量
public T get() {
Thread t = Thread.currentThread();//得到当前的线程
ThreadLocalMap map = getMap(t);//根据当前线程获得一个ThreadLocalMap
if (map != null) {//如果不为空
ThreadLocalMap.Entry e = map.getEntry(this);//根据当前对象获得Entry
if (e != null) {//如果本地变量存在,返回值
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
//否则调用setInitialValue方法
return setInitialValue();
}

getMap方法

//返回当前线程的threadLocals变量
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}

threadLocals的声明

//其实就是一个ThreadLocalMap类型的变量
ThreadLocal.ThreadLocalMap threadLocals = null;

ThreadLocalMap

//ThreadLocalMap里有Entry内部类,用于存放键值对
static class ThreadLocalMap {
static class Entry extends WeakReference<ThreadLocal<?>> {
Object value; Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
.....以下省略
}

setInitialValue方法

private T setInitialValue() {
T value = initialValue();//调用initialValue方法,初始化本地变量的值,如果不覆盖该方法,返回null
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);//根据当前线程获取ThreadLocalMap
if (map != null)//如果map不为空
map.set(this, value);//设置键值对
else
createMap(t, value);//否则创建map
return value;
}

createMap方法

void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}

至此可以知道ThreadLocal如何为每个线程创建变量副本了,每个线程Thread内部有一个ThreadLocal.ThreadLocalMap类型的成员变量threadLocals,这个threadLocals就是用来存储实际的变量副本的,存储以ThreadLocal为键,本地线程变量为值的键值对。

remove操作

//先获取当前线程的ThreadLocalMap,然后删除当前ThreadLocal对象
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
}

java.lang.ThreadLocal源码分析的更多相关文章

  1. 【JAVA】ThreadLocal源码分析

    ThreadLocal内部是用一张哈希表来存储: static class ThreadLocalMap { static class Entry extends WeakReference<T ...

  2. java.lang.StringBuffer源码分析

    StringBuffer是一个线程安全的可变序列的字符数组对象,它与StringBuilder一样,继承父类AbstractStringBuilder.在多线程环境中,当方法操作是必须被同步,Stri ...

  3. java.lang.StringBuilder源码分析

    StringBuilder是一个可变序列的字符数组对象,它继承自AbstractStringBuilder抽象类.它不保证同步,设计出来的目的是当这个字符串缓存只有单线程使用的时候,取代StringB ...

  4. java.lang.Runnable 源码分析

    子接口:RunnableFuture<V>, RunnableScheduledFuture<V> 实现类:AsyncBoxView.ChildState, ForkJoinW ...

  5. Java并发编程之ThreadLocal源码分析

    ## 1 一句话概括ThreadLocal<font face="微软雅黑" size=4>  什么是ThreadLocal?顾名思义:线程本地变量,它为每个使用该对象 ...

  6. Java多线程学习之ThreadLocal源码分析

    0.概述 ThreadLocal,即线程本地变量,是一个以ThreadLocal对象为键.任意对象为值的存储结构.它可以将变量绑定到特定的线程上,使每个线程都拥有改变量的一个拷贝,各线程相同变量间互不 ...

  7. ThreadLocal源码分析-黄金分割数的使用

    前提 最近接触到的一个项目要兼容新老系统,最终采用了ThreadLocal(实际上用的是InheritableThreadLocal)用于在子线程获取父线程中共享的变量.问题是解决了,但是后来发现对T ...

  8. 并发编程(四)—— ThreadLocal源码分析及内存泄露预防

    今天我们一起探讨下ThreadLocal的实现原理和源码分析.首先,本文先谈一下对ThreadLocal的理解,然后根据ThreadLocal类的源码分析了其实现原理和使用需要注意的地方,最后给出了两 ...

  9. 并发-ThreadLocal源码分析

    ThreadLocal源码分析 参考: http://www.cnblogs.com/dolphin0520/p/3920407.html https://www.cnblogs.com/coshah ...

随机推荐

  1. 对javascript this的理解

    对于this的理解,大部分时间都比较模糊,最近几天做了一些研究,记录一下 首先应该明白,this是执行上下文的一个属性,它的值取决于执行上下文,执行上下文和函数调用方式相关,定义一个function的 ...

  2. 关于egg的压缩测试报告

     167274doc  单字分词 全压缩 时间  real 15m58.464suser 13m52.157ssys 2m3.445s   空间 tmpfs 12G 1.5G 11G 13% /ape ...

  3. ubuntu13.04装配oracle11gR2

    http://jingyan.baidu.com/album/bea41d435bc695b4c41be648.html?picindex=2 http://www.360doc.com/conten ...

  4. eclipse中的tomcat debug模式启动报超时45s

    在eclipse中加入tomcat,开debug模式非常好用,这里就不介绍了 最近eclipse的tomcat开debug模式就是启动不了,增加时间也不能解决,但是非debug模式就可以打开,我觉得是 ...

  5. Linux上安装Mysql+Apache+Php

    一.安装Mysql 1.卸载默认的mysql yum -y remove mysql-libs-* Removed:  mysql-libs.x86_64 0:5.1.73-3.el6_5 卸载成功 ...

  6. SQL操作XML

    前面一段时间为了赶项目的进度,一直在加班,现在空闲了下来将前面碰到的问题整理了一下,发现了一些十分有用的,在此记录下来,看能不能帮助到遇到同样问题的朋友,此文仅是自己个人的意见,若存在问题,还望不宁赐 ...

  7. MyBatis优化技巧

    ☬配置日志文件 封装工具类 代码贴一下: package com.shxt.utils; import java.io.InputStream; import org.apache.ibatis.io ...

  8. 通过继承nsoperation的方法--处理复杂任务

    #import <Foundation/Foundation.h> @class TTOperation; @protocol TTOperationDelegate <NSObje ...

  9. C++重载自增/减操作符

    作为类成员使用. 前缀是先加/减1,再取值:后缀是先取值,再加/减1. 前缀是左值,返回引用:后缀是右值,返回值. 后缀多一个int参数进行区分,用时编译器会传个没用的0作实参. 在后缀实现中调用前缀 ...

  10. Android小项目之七 应用程序的更新安装

    ------- 源自梦想.永远是你IT事业的好友.只是勇敢地说出我学到! ---------- 按惯例,写在前面的:可能在学习Android的过程中,大家会和我一样,学习过大量的基础知识,很多的知识点 ...