Java学习笔记(1)——ThreadLocal类的使用

主要是对博客的一些自己的理解和补充  地址:http://www.cnblogs.com/-new/p/7604420.html

概述:

  这里套用该博主的实验代码:

   

public class T {
    ThreadLocal<Long> longLocal = new ThreadLocal<Long>();
    public void set() {
        longLocal.set(Thread.currentThread().getId());
    }
    public long getLong() {
        return longLocal.get();
    }
    public static void main(String[] args) throws InterruptedException {
        final T test = new T();
        test.set();
        Thread thread1 = new Thread(){
            public void run() {
                test.set();
                System.out.println("线程一:"+test.getLong());
            };
        };
        thread1.start();
        thread1.join();
        System.out.println("main线程:"+test.getLong());
        System.out.println("没有发生值的覆盖,两个线程保存的值是不同的");
    }
}

  1、基本分析

  • 对于主线程和thread1两个线程来说,他们共享了T类的test这个对象,这个时候两者可以通过ThreadLocal类来分别保存一个test对象里面的值;也就是说:test对象不变,但是里面有一个变量是因使用test这个对象不同而不同的,longLocal变量就是这个变量
  • 它的底层是使用一个ThreadLocalMap来实现的(每一个Thread里面都有这个对象),里面的Entry键名为某一个对象的ThreadLocal的实例,键值为具体的值,一个线程可以绑定多个ThreadLocal对象; 并且,Thread对象的成员ThreadLocalMap是懒加载的,用到的时候才加载:(注意:这里的threadLocals是线程t的一个成员变量ThreadLocalMap的实例)

     /**
         * 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) {
            t.threadLocals = new ThreadLocalMap(this, firstValue);
        }

    这里是使用ThreadLocal对象的实例作为Entry的键名

    /**
             * Construct a new map initially containing (firstKey, firstValue).
             * ThreadLocalMaps are constructed lazily, so we only create
             * one when we have at least one entry to put in it.
             */
            ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
                table = new Entry[INITIAL_CAPACITY];
                int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
                table[i] = new Entry(firstKey, firstValue);
                size = 1;
                setThreshold(INITIAL_CAPACITY);
            }

    这里是set方法的源码,使用的是开地址法

     /**
             * Set the value associated with key.
             *
             * @param key the thread local object
             * @param value the value to be set
             */
            private void set(ThreadLocal<?> key, Object value) {
    
                // We don‘t use a fast path as with get() because it is at
                // least as common to use set() to create new entries as
                // it is to replace existing ones, in which case, a fast
                // path would fail more often than not.
    
                Entry[] tab = table;
                int len = tab.length;
                int i = key.threadLocalHashCode & (len-1);
    
                for (Entry e = tab[i];
                     e != null;
                     e = tab[i = nextIndex(i, len)]) {
                    ThreadLocal<?> k = e.get();
    
                    if (k == key) {
                        e.value = value;
                        return;
                    }
    
                    if (k == null) {
                        replaceStaleEntry(key, value, i);
                        return;
                    }
                }
    
                tab[i] = new Entry(key, value);
                int sz = ++size;
                if (!cleanSomeSlots(i, sz) && sz >= threshold)
                    rehash();
            }

    2、可能存在的问题:内存泄漏

    注意:由于ThreadLocal.ThreadLocalMap.Entry继承自弱连接,当强连接断了之后,下一次GC就可以释放键名ThreadLocal对象的内存。 但是,value:在ThreadLocal.ThreadLocalMap.Entry中使用的强连接,无法由程序自动GC,必须通过remove、set、get等方法触发GC

    /**
             * The entries in this hash map extend WeakReference, using
             * its main ref field as the key (which is always a
             * ThreadLocal object).  Note that null keys (i.e. entry.get()
             * == null) mean that the key is no longer referenced, so the
             * entry can be expunged from table.  Such entries are referred to
             * as "stale entries" in the code that follows.
             */
            static class Entry extends WeakReference<ThreadLocal<?>> {
                /** The value associated with this ThreadLocal. */
                Object value;
    
                Entry(ThreadLocal<?> k, Object v) {
                    super(k);
                    value = v;
                }
            }

    ps:第一次写博客,写的也只是自己的一些心得体会,有什么不足之处欢迎指出

原文地址:https://www.cnblogs.com/douglasdoudou/p/8849147.html

时间: 2024-10-03 00:32:42

Java学习笔记(1)——ThreadLocal类的使用的相关文章

非专业码农 JAVA学习笔记 6java工具类和算法-string

续<非专业码农 JAVA学习笔记 5 java工具类和算法> 五.字符串string 字符串和字符的差别:字符串双引号括起来”n”,字符用单引号括起来,表示一种符号’\n’ 1.string的主要方法和属性 类 方法或者属性 备注 定义string Stirng s=new string(“值”),string s=”值” 属性 string.length:string的长度为字节 方法startswith,endswith s.startwith(“值”)-以值为开头,s.endswith(

【原】Java学习笔记031 - 常用类

1 package cn.temptation; 2 3 public class Sample01 { 4 public static void main(String[] args) { 5 /* 6 * 类 Math:包含用于执行基本数学运算的方法,如初等指数.对数.平方根和三角函数. 7 * 8 * Math类的常用字段: 9 * static double E :比任何其他值都更接近 e(即自然对数的底数)的 double 值. 10 * static double PI :比任何其他

java学习笔记7--抽象类与抽象方法

1.终结类与终结方法 被final修饰符修饰的类和方法,终结类不能被继承,终结方法不能被当前类的子类重写 终结类的特点:不能有派生类 终结类存在的理由: 安全: 黑客用来搅乱系统的一个手法是建立一个类的派生类,然后用他们的类代替原来的类 设计: 你认为你的类是最好的或从概念上你的类不应该有任何派生类 终结方法的特点:不能被派生类覆盖 终结方法存在的理由: 对于一些比较重要且不希望子类进行更改的方法,可以声明为终结方法.可防止子类对父类关键方法的错误重写,增加了代码的安全性和正确性 提高运行效率.

java学习笔记—实现一个类MyInputStream(28)

1 实现一个类MyInputStream读取文件,且不能抛出异常 public class TestDemo { public static void main(String[] args) throws Exception { InputStream in = new MyInputStream("d:/a/a.txt"); byte[] b = new byte[1024]; int len = 0; while((len=in.read(b))!=-1){ String s =

黑马程序员——JAVA学习笔记七(String类)

1,    String类一旦被初始化就不会被改变. 字符串不不能被改变,编译可以让字符串之间共享.编译器将各种字符串存放在公共的存储池子中.字符串变量指向存储池中相应的位置.实际上只有字符串常量.而+(除了常量相加)和其它方法操作的不是共享的. String s1 ="abc" ,String s2 = "abc" (他们存在公共池中),String s3 = new String ("abc"),存在堆中; 则s1== s2; s1! = s

java学习笔记之Arrays类(二分查找)

import java.io.*; import java.util.*; import java.math.*; import java.text.*; public class Main { public static void main(String[] args){ Scanner in=new Scanner(System.in); int x,n; while(in.hasNext()){ n=in.nextInt(); int[] a=new int[n]; for(int i=0

java学习笔记10--泛型总结

java学习笔记系列: java学习笔记9--内部类总结 java学习笔记8--接口总结 java学习笔记7--抽象类与抽象方法 java学习笔记6--类的继承.Object类 java学习笔记5--类的方法 java学习笔记4--对象的初始化与回收 java学习笔记3--类与对象的基础 java学习笔记2--数据类型.数组 java学习笔记1--开发环境平台总结 本文地址:http://www.cnblogs.com/archimedes/p/java-study-note10.html,转载

java学习笔记8--接口总结

接着前面的学习: java学习笔记7--抽象类与抽象方法 java学习笔记6--类的继承.Object类 java学习笔记5--类的方法 java学习笔记4--对象的初始化与回收 java学习笔记3--类与对象的基础 java学习笔记2--数据类型.数组 java学习笔记1--开发环境平台总结 本文地址:http://www.cnblogs.com/archimedes/p/java-study-note8.html,转载请注明源地址. 生活中的接口: 什么是接口? 一个Java接口是一些方法特

java学习笔记14--多线程编程基础1

本文地址:http://www.cnblogs.com/archimedes/p/java-study-note14.html,转载请注明源地址. 多线程编程基础 多进程 一个独立程序的每一次运行称为一个进程,例如:用字处理软件编辑文稿时,同时打开mp3播放程序听音乐,这两个独立的程序在同时运行,称为两个进程 进程要占用相当一部分处理器时间和内存资源 进程具有独立的内存空间 通信很不方便,编程模型比较复杂 多线程 一个程序中多段代码同时并发执行,称为多线程,线程比进程开销小,协作和数据交换容易

java学习笔记12--异常处理

java学习笔记系列: java学习笔记11--集合总结 java学习笔记10--泛型总结 java学习笔记9--内部类总结 java学习笔记8--接口总结 java学习笔记7--抽象类与抽象方法 java学习笔记6--类的继承.Object类 java学习笔记5--类的方法 java学习笔记4--对象的初始化与回收 java学习笔记3--类与对象的基础 java学习笔记2--数据类型.数组 java学习笔记1--开发环境平台总结 本文地址:http://www.cnblogs.com/arch