MyException - 我的异常网
当前位置:我的异常网» 综合 » java中的摘引与ThreadLocal

java中的摘引与ThreadLocal

www.MyException.Cn  网友分享于:2013-09-28  浏览:0次
java中的引用与ThreadLocal

ThreadLocal

前几天看了@华为kim的threadlocal的博文深有感触,所有在这再次总结一下我对threadlocal的源码理解,以及内部机制。 

数据结构

下面看一下threadlocal的数据结构:每一个Thread内部都有一个 ThreadLocal.ThreadLocalMap threadLocals 对象 , 而ThreadLocalMap 中,维护着一个Entry[]数组,每个Entry对象,包含一个弱引用的ThreadLocal和一个value。

内部机制

SET操作

 public void set(T value) {
        //获取当前线程
        Thread t = Thread.currentThread();
        //根据当前线程,找到线程内部的ThreadLocalMap
        ThreadLocalMap map = getMap(t);
        if (map != null)  //赋值  当前的ThreadLocal  和  value
            map.set(this, value);
        else   //创建线程内部的ThreadLocalMap
            createMap(t, value);
    }    

GET操作

public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            //根据当前ThreadLocal为key,获取对应的Entry,并获取value
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        //返回默认值
        return setInitialValue();
    }

原理分析

1)为什么ThreadLocalMap要用WeakReference来封装key?

static class Entry extends WeakReference<ThreadLocal<?>> {
    /** The value associated with this ThreadLocal. */
    Object value;
    Entry(ThreadLocal<?> k, Object v) {
         super(k);
         value = v;
         }
    }
WeakReference有以下特性:
  当一个对象A只有WeakReference引用指向它是,那么A在下一次gc的时候就会被回收掉。想象下,如果ThreadLocalMap中某个key已经不用了,最终只会有一个WeakReference指向它,
  这个key自然就可以被回收掉,不会一直停留在ThreadLocalMap中。(对引用将在后面详细介绍)
 
如果ThreadLocal被回收掉了,那么value怎么回收?
  在ThreadLocalMap的get和set方法中,根据ThreadLocal经过hash,获取到的Entry,如果Entry的key=null,执行expungeStaleEntry(i)方法,该方法的主要操作把哈希表当前位置的无用数据清理掉(当然还有别的操作)。
 
总之,假设某个threadlocal对象无效,这个对象本身会在下次gc被回收,对应的value值也会在某次ThreadLocal调用中被释放;如果某个thread死掉了,它对应的threadlocal内容自动释放。
 
2)为什么要用开放地址实现Hash冲突呢?
ThreadLocalMap的 Entry[] table 表不同于HashMap的链表法解决冲突。

  a. 节省内存空间,链表使用的空间大于数组;
  b. threadLocalMap设计的哈希key可以尽可能避免哈希冲突;
  c. 清理数据效率高,毕竟遍历数组比遍历链表效率高;

 java中的引用

 在深入理解JVM一书中,谈及了强引用,软引用,弱引用,虚引用。但笔者没有当时深入研究,下面是对java中引用的详细总结。

WeakHashMap

在介绍引用之前,先来看一下WeakHashMap的实现原理,先给出下面的测试用例,

public class test {
  public static void main(String[] args) {
    Map<Integer, Object> map = new HashMap<>();
    for (int i = 0; i < 10000; i++) {
      Integer ii = new Integer(i);
      map.put(ii, new byte[i]);
    }
  }
}

//内存溢出
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at com.test.test.main(test.java:18)

//将HashMap改成WeakHashMap
无任何报错

 实际上,WeakHashMap指定了弱键,当只有一个弱引用指向该key,那么在内存不足,下次GC的时候清除该域。此外,在WeakHashMap的set(),get(),size()操作中,都间接或者直接调用了expungeStaleEntries()方法,以清理持有弱引用的key的表项。 

  private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V> {
        V value;
        final int hash;
        Entry<K,V> next;

        /**
         * Creates new entry.
         */
        Entry(Object key, V value,
              ReferenceQueue<Object> queue,
              int hash, Entry<K,V> next) {
            super(key, queue);
            this.value = value;
            this.hash  = hash;
            this.next  = next;
        }

 软引用与弱引用

引用的使用十分广泛,对强引用和虚引用就不一一介绍了,下面重点介绍两个引用,软引用和弱引用。

看下面示例:

public class test {
  public static void main(String[] args) {
    /*Test1*/
    Pojo pojo = new Pojo("Test1");
    WeakReference<Pojo> sr = new WeakReference<Pojo>(pojo);
    //如果添加下面的软应引用,而软引用只有在内存不足的情况下才会删除对象,所有会打印 Test1
    //SoftReference<Pojo> sf = new SoftReference<Pojo>(pojo);
    pojo = null;
    //此时只有一个弱引用指向对象
    System.gc();
    System.out.println(sr.get());   //null

  }
  static class Pojo {
    String value;
    Pojo(String value) {
      this.value = value;
    }
    public String toString() {
      return this.value;
    }
  }
}

总结

WeakReference:每次gc的时候,如果一个对象A只被WeakReference直接引用,那么A就可以被回收掉;
SoftReference:每当内存不足的时候(其实和WeakReference差不多),如果一个对象A只被SoftReference或WeakReference直接引用,那么A就可以被回收掉;
注意:内存不足或者gc的时候,回收的不是reference对象本身,而是reference所引用的对象。



 

文章评论

鲜为人知的编程真相
鲜为人知的编程真相
“懒”出效率是程序员的美德
“懒”出效率是程序员的美德
一个程序员的时间管理
一个程序员的时间管理
Java 与 .NET 的平台发展之争
Java 与 .NET 的平台发展之争
看13位CEO、创始人和高管如何提高工作效率
看13位CEO、创始人和高管如何提高工作效率
为什么程序员都是夜猫子
为什么程序员都是夜猫子
那些争议最大的编程观点
那些争议最大的编程观点
亲爱的项目经理,我恨你
亲爱的项目经理,我恨你
10个调试和排错的小建议
10个调试和排错的小建议
程序员眼里IE浏览器是什么样的
程序员眼里IE浏览器是什么样的
老美怎么看待阿里赴美上市
老美怎么看待阿里赴美上市
程序员和编码员之间的区别
程序员和编码员之间的区别
旅行,写作,编程
旅行,写作,编程
写给自己也写给你 自己到底该何去何从
写给自己也写给你 自己到底该何去何从
编程语言是女人
编程语言是女人
5款最佳正则表达式编辑调试器
5款最佳正则表达式编辑调试器
十大编程算法助程序员走上高手之路
十大编程算法助程序员走上高手之路
Web开发者需具备的8个好习惯
Web开发者需具备的8个好习惯
什么才是优秀的用户界面设计
什么才是优秀的用户界面设计
每天工作4小时的程序员
每天工作4小时的程序员
我是如何打败拖延症的
我是如何打败拖延症的
程序员必看的十大电影
程序员必看的十大电影
漫画:程序员的工作
漫画:程序员的工作
代码女神横空出世
代码女神横空出世
60个开发者不容错过的免费资源库
60个开发者不容错过的免费资源库
我的丈夫是个程序员
我的丈夫是个程序员
程序员的一天:一寸光阴一寸金
程序员的一天:一寸光阴一寸金
科技史上最臭名昭著的13大罪犯
科技史上最臭名昭著的13大罪犯
我跳槽是因为他们的显示器更大
我跳槽是因为他们的显示器更大
 程序员的样子
程序员的样子
Java程序员必看电影
Java程序员必看电影
程序员最害怕的5件事 你中招了吗?
程序员最害怕的5件事 你中招了吗?
程序员周末都喜欢做什么?
程序员周末都喜欢做什么?
程序员都该阅读的书
程序员都该阅读的书
10个帮程序员减压放松的网站
10个帮程序员减压放松的网站
2013年美国开发者薪资调查报告
2013年美国开发者薪资调查报告
为啥Android手机总会越用越慢?
为啥Android手机总会越用越慢?
初级 vs 高级开发者 哪个性价比更高?
初级 vs 高级开发者 哪个性价比更高?
中美印日四国程序员比较
中美印日四国程序员比较
要嫁就嫁程序猿—钱多话少死的早
要嫁就嫁程序猿—钱多话少死的早
2013年中国软件开发者薪资调查报告
2013年中国软件开发者薪资调查报告
那些性感的让人尖叫的程序员
那些性感的让人尖叫的程序员
做程序猿的老婆应该注意的一些事情
做程序猿的老婆应该注意的一些事情
如何成为一名黑客
如何成为一名黑客
Web开发人员为什么越来越懒了?
Web开发人员为什么越来越懒了?
“肮脏的”IT工作排行榜
“肮脏的”IT工作排行榜
程序员应该关注的一些事儿
程序员应该关注的一些事儿
程序员的鄙视链
程序员的鄙视链
聊聊HTTPS和SSL/TLS协议
聊聊HTTPS和SSL/TLS协议
软件开发程序错误异常ExceptionCopyright © 2009-2015 MyException 版权所有