ThreadLocal的set方法和get方法,从set方法开始:
public void set(T value) {
Thread t = Thread.currentThread();//获取当前线程
ThreadLocalMap map = getMap(t);//获取线程的局部变量
if (map != null)//判断map是否存在
map.set(this, value);//set值 key是当前ThreadLocal对象 value是value
else
createMap(t, value);//否则 创建一个map设置值
}
     get方法:
public T get() {
Thread t = Thread.currentThread();//获取当前线程
ThreadLocalMap map = getMap(t);//获取线程的局部变量map
if (map != null) {//当map存在时
ThreadLocalMap.Entry e = map.getEntry(this);//获取entry(键值对)
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;//返回值
}
}
return setInitialValue();//返回null
}
     在了解了ThreadLocal的内部实现后,我看到一个问题,那就是这些变量是维护在Thread类内部的,这也意味着只要线程不退出,对象的引用将一直存在,
     当线程退出是,Thread类会进行一些清理工作,其中就包括清理ThreadLocalMap.下面是具体实现:在Thread类内部:
private void exit() {
if (group != null) {
group.threadTerminated(this);
group = null;
}
/* Aggressively null out all reference fields: see bug 4006245 */
target = null;
/* Speed the release of some of these resources */
threadLocals = null;
inheritableThreadLocals = null;
inheritedAccessControlContext = null;
blocker = null;
uncaughtExceptionHandler = null;
}
     因此,如果我们使用线程池,那就意味着当前线程未必会退出,(比如固定大小的线程池,线程总是存在的,) 如果这样,将一些大大的对象设置到ThreadLocal中,可能会使系统出现内存在泄漏,
     此时,你希望及时的GC,最好使用ThreadLocal.remove()方法将这个变量移除,就像我们习惯性的关闭数据库链接一样,如果你确定不需要这个对象了,那么就应该告诉虚拟机,把他回收掉,防止内存泄漏,
     另外一种有趣的情况是JDK也可能允许你想释放普通变量一样释放ThreadLocal.比如,我么你有时候为了加入GC.会特意写出类似obj=null之类的代码.如果这么做,obj所指向的对象就会更容易地垃圾回收器发现,从而加速回收,
     同理,如果对于ThreadLocal的变量,我们也手动将其设置null.比如t1=null.那么这个ThreadLocal对应的所有线程的局部变量都有可能被回收,我们写个小例子来看一看奥秘:
public class ThreadLocalDemo_Gc {
static volatile ThreadLocal<SimpleDateFormat> t1 = new ThreadLocal<SimpleDateFormat>() {
@Override
protected void finalize() throws Throwable { //重载了finalize() 当对象在GC时,打印信息
System.out.println(this.toString() + " is gc");
}
}; static volatile CountDownLatch cd = new CountDownLatch(10000);//倒计时 public static class ParseDate implements Runnable {
int i = 0; public ParseDate(int i) {
this.i = i;
} @Override
public void run() {
try {
if (t1.get() == null) {
t1.set(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") {
@Override
protected void finalize() throws Throwable {
System.out.println(this.toString() + " is gc");
}
});
System.out.println(Thread.currentThread().getId() + ":create SimpleDateFormat");
}
Date t = t1.get().parse("2016-12-19 19:29:" + i % 60);
} catch (ParseException e) {
e.printStackTrace();
} finally {
cd.countDown();//完成 计数器减1
}
}
} public static void main(String[] args) throws InterruptedException {
ExecutorService es = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10000; i++) {
es.execute(new ParseDate(i));
}
cd.await();//等待所有线程 完成准备
System.out.println("mission complete!!");
t1 = null;
System.gc();
System.out.println("first GC complete!!");
t1 = new ThreadLocal<>();
cd = new CountDownLatch(1000);
for (int i = 0; i < 10000; i++) {
es.execute(new ParseDate(i));
}
cd.await();
Thread.sleep(1000);
System.gc();
System.out.println("second GC complete!!");
}
}
     输出结果如下:
     在主函数Main中,先后进行了2次任务提交,每次10000个任务,在第一次任务提交后,我们t1设置为null 接着进行了一次gc,接着我们进行了第二次任务提交,完成后在进行一次gc,
     注意这些输出,.我们发现了当t1被设置为null时候,第一次gc 回收了.接着提交第二次任务,这次我们也是创建了10个线程,可以看到,虽然我们手动remove()这些对象,但是系统依然有可能回收他们.
     要了解这里的回收机制,我们需要进一步了解Thread.ThreadLocalMap的实现,之前我们说过,ThreadLocalMap是一个类似HashMap的东西,更精确地说,他更加类似WeakHashMap.
     ThreadLocalMap的实现使用了弱引用,弱引用是比强引用弱的多的引用,java在虚拟机回收时,如果发现若引用,就会立即回收,ThreadLocalMap内部由一系列Entry构成,每一个entry都是WeakReferenc<ThreadLocal>:

static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value; Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
      这里的参数k就是map的key,v就是Map的value.其中k也就是ThreadLocal实例,作为弱引用使用(super(k)就是调用了WeakReferenc的构造函数,)因此,索然这里使用了ThreadLocal作为map的key,但是实际上,他并不是真的持有ThreadLocal的引用,而当THreadLocal的外部引用被回收时,ThreadLocalMap中的key就会变成null.当系统进行ThreadLocalMap清理时,就会自然将这些垃圾数据回收, 

ThreadLocal的实现原理(读书笔记)的更多相关文章

  1. <<操作系统精髓与设计原理>>读书笔记(一) 并发性:互斥与同步(1)

    <<操作系统精髓与设计原理>>读书笔记(一) 并发性:互斥与同步 并发问题是所有问题的基础,也是操作系统设计的基础.并发包括很多设计问题,其中有进程间通信,资源共享与竞争,多个 ...

  2. 深入探索Android热修复技术原理读书笔记 —— 热修复技术介绍

    1.1 什么是热修复 对于广大的移动开发者而言,发版更新是最为寻常不过的事了.然而,如果你 发现刚发出去的包有紧急的BUG需要修复,那你就必须需要经过下面这样的流程: 这就是传统的更新流程,步骤十分繁 ...

  3. 深入探索Android热修复技术原理读书笔记 —— 代码热修复技术

    在前一篇文章 深入探索Android热修复技术原理读书笔记 -- 热修复技术介绍中,对热修复技术进行了介绍,下面将详细介绍其中的代码修复技术. 1 底层热替换原理 在各种 Android 热修复方案中 ...

  4. 深入探索Android热修复技术原理读书笔记 —— 资源热修复技术

    该系列文章: 深入探索Android热修复技术原理读书笔记 -- 热修复技术介绍 深入探索Android热修复技术原理读书笔记 -- 代码热修复技术 1 普遍的实现方式 Android资源的热修复,就 ...

  5. 深入探索Android热修复技术原理读书笔记 —— so库热修复技术

    热修复系列文章: 深入探索Android热修复技术原理读书笔记 -- 热修复技术介绍 深入探索Android热修复技术原理读书笔记 -- 代码热修复技术 深入探索Android热修复技术原理读书笔记 ...

  6. LOMA280保险原理读书笔记

    LOMA是国际金融保险管理学院(Life Office Management Association)的英文简称.国际金融保险管理学院是一个保险和金融服务机构的国际组织,它的创建目的是为了促进信息交流 ...

  7. Spark基本工作流程及YARN cluster模式原理(读书笔记)

    Spark基本工作流程及YARN cluster模式原理 转载请注明出处:http://www.cnblogs.com/BYRans/ Spark基本工作流程 相关术语解释 Spark应用程序相关的几 ...

  8. 通信原理读书笔记:常规AM调制的功率

    Proakis,通信系统原理,p101: 两个不同频率正弦和的功率为其功率的和. 计算功率时,和的平方展开后会出现两个正弦乘积项,按积化和差展开后在公共周期内积分为零.

  9. ThreadLocal的简单使用(读书笔记)

         从ThreadLocal的名字上可以看到,这是一个线程局部变量,也就是说,只有当前线程可以访问,既然是只有当前线程可以访问的数据,自然是线程安全的. public class ThreadL ...

随机推荐

  1. win 7 浏览器被篡改小插曲

    今天下班回家,打开台式机发现IE,火狐都被篡改了.作为运维都会有点强迫症.这是个桌面系统,实在是没兴趣捣鼓.但是还是没办法,经常要用.等我下次有空了,直接换linux好了. 于是开始排查问题吧: 1. ...

  2. Selenium2+python自动化22-发送各种类型附件邮件【转载】

    前言 最近一些小伙伴,在搞邮箱的事情,小编于是去折腾了一下!总结了一些干货,与大家分享一下!速来,抱大腿,我要开车了! 基本思路就是,使用MIMEMultipart来标示这个邮件是多个部分组成的,然后 ...

  3. seneca的一段代码(原创)

    var seneca=require('seneca')() seneca.add({cmd:'wordcount'},function(msg,respond){ var length=0; if( ...

  4. portainer,用于管理docker swarm,好像也不错哟

    shipyard的模式,好像在docker 1.12之后,没有啥用武之地了,也没有更新. 接下来,集群管理和调度,最有知名度的就是rancher了. 在rancher之前,我们试一下portainer ...

  5. PostgreSQL教程

    https://www.yiibai.com/postgresql/ https://blog.csdn.net/zhangzeyuaaa/article/details/77941039

  6. 拓扑排序(Topological Order)UVa10305 Ordering Tasks

    2016/5/19 17:39:07 拓扑排序,是对有向无环图(Directed Acylic Graph , DAG )进行的一种操作,这种操作是将DAG中的所有顶点排成一个线性序列,使得图中的任意 ...

  7. 训练指南 UVA - 11090(最短路BellmanFord+ 二分判负环)

    layout: post title: 训练指南 UVA - 11090(最短路BellmanFord+ 二分判负环) author: "luowentaoaa" catalog: ...

  8. Reference resources

    CentOS7 (精简操作指令) http://www.centoscn.com/CentOS/help/2016/0429/7147.html

  9. java中的3大特性之继承

    继承的特点:继承父类的属性和方法.单继承(多层继承)c++里的继承是多继承 特性 :方法的复写(重写) java中的继承和OC中一样. 比如:人可以养狗; 人---->狗 :整体和部分(拥有)关 ...

  10. Exercise02_01

    import java.util.Scanner; public class Out { public static void main(String[] args){ Scanner input = ...