• Thread&ThreadLocal


    Thread类

    有许多重载的构造器

    new Thread(……)

    调用构造器,在构造器中会调用init方法

      在init方法中,调用currentThread()方法获得当前正在创建新线程的线程,并将新线程的daemon、priority、contextClassLoader、target、stackSize等设置为和创建新线程的线程一致。this.inheritableThreadLocals =ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);(子线程继承父线程的相关设置)

      在init方法中,并不会初始化Thread类的ThreadLocal.ThreadLocalMap类型的成员变量,而是在当前线程中,调用了ThreadLocal的get或者set方法时,才会初始化该属性。

     

     

    在当前线程中,可以创建一个或者多个ThreadLocal类型的变量

    public class TestThreadLocal2 {
        private static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>();
        private static ThreadLocal<String> threadLocal2 = new ThreadLocal<String>();
        @Test
        public void test(){
            for(int i=0;i<5;i++){
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        threadLocal.set((int) (Math.random()*100));
                        threadLocal2.set("------");
                        System.out.println(threadLocal.get()+threadLocal2.get()+"  "+Thread.currentThread().getName());;                
                    }
                }).start();
            }
            threadLocal.set((int) (Math.random()*100));
            threadLocal2.set("======");
            System.out.println(threadLocal.get()+threadLocal2.get()+"  "+Thread.currentThread().getName());;
    
        }
    }

     ThreadLocal

    线程本地存储,每个线程都拥有自己的线程本地存储,线程私有,线程隔离

    This class provides thread-local variables

    每个线程都拥有独立的共享变量的副本,副本只对当前线程可见,当前线程对副本的修改不会影响其他线程

    ThreadLocal实例通常定义为private static

    只要线程还是活的并且ThreadLocal实例是可访问的,每个线程都保持对线程本地变量的副本的隐式引用

    线程死亡之后,垃圾回收回回收线程的本地变量的所有副本

    Thread类的threadLocals属性在调用ThreadLocal的get或者set方法时初始化

    ThreadLocal是如何为每个线程创建共享变量的副本的?

      Thread类有一个ThreadLocal.ThreadLocalMap类型的成员变量threadLocals,threadLocals就用来存储每个线程的变量副本

      创建线程、线程初始化之后,threadLocals仍为null,在调用ThreadLocal对象的get或者set方法时,才会初始化threadLocals

      变量的副本实际存储在Thread类的threadLocals成员变量中

      threadLocals是ThreadLocal.ThreadLocalMap类型,ThreadLocalMap是ThreadLocal的静态内部类,成员内部类Entry

        存储当前线程的变量副本:private void set(ThreadLocal key, Object value)

        键:this,当前ThreadLocal类的实例,因为一个线程可能有多个ThreadLocal对象,所以使用ThreadLocal类的实例作为ThreadLocalMap的键

        值:value,要保存的变量的副本

        在当前线程中使用变量副本:private Entry getEntry(ThreadLocal key)       entry.value

      

     

    1.get(调用ThreadLocal对象的get方法,获取当前线程的threadlocals成员变量中保存的键为this的value,该value值即为线程的变量副本)

    (1)获取当前线程t   Thread.currentThread()

    (2)调用getmap(t),获取与当前线程绑定的ThreadLocalMap对象map

      getMap方法:直接返回当前线程的成员变量threadLocals(ThreadLocal.ThreadLocalMap类型)

    (3)如果map不为空,从map获取ThreadLocal在当前线程中保存的变量副本

      map.getEntry(this)     this是ThreadLocal的对象

        如果从map中找到了,直接返回

    (4)如果map为空,或者从map中找不到键this对应的Entry

      调用setInitialValue()方法

      在setInitialValue()方法中

          首先,返回初始化值value,调用initialValue()(protected方法,返回null,因此,如果在set之前get,会空指针异常;一定要在get之前set,就应该在创建private static的ThreadLocal对象时,重写initialValue方法,返回一个初始化值)

          然后,如果map是空,调用createMap(t,value)初始化当前线程的threadlocals成员变量

             如果map不为空(当前map中,没有this对应的Entry),map.set(this,value)

     

    2.set(value)(调用ThreadLocal对象的set方法,在当前线程的threadLocals成员变量中保存一个键为this,值为value的共享变量副本)

    (1)获得当前线程t 

      Thread.currentThread();

    (2)获得当前线程的ThreadLocalMap成员变量

      ThreadLocalMap map = getMap(t);(getMap方法直接返回t.threadLocals)

    (3)map不为空

      map.set(this, value);

    (4)map为空

      createMap(t, value);(在createMap方法中,初始化Thread类的threadLocals成员变量t.threadLocals = new ThreadLocalMap(this, firstValue);)

     

    3.remove(调用ThreadLocal对象的remove方法,移除当前线程的threadlocals对象中键为this的entry)

    (1)获得当前线程的ThreadLocalMap对象

      ThreadLocalMap m = getMap(Thread.currentThread());

    (2)m.remove(this);

     

     ThreadLocalMap

    ThreadLocal的静态内部类

    Thread类的ThreadLocal.ThreadLocalMap类型的成员变量threadLocals,该成员变量实际就是存储了当前线程的变量副本(map)

     Entry继承WeakReference

      弱引用问题

        ThreadLocal已经被回收了,ThreadLocalMap中可能存在键为null的键值对

      解决:将ThreadLocal定义为private static

         调用remove清除

  • 相关阅读:
    wcf 调试
    adf 笔记
    oracle 自定义比较函数
    【SpringMVC】SpringMVC系列3之@PathVariable映射URL占位符参数
    【SpringMVC】SpringMVC系列2之@RequestMapping 映射约束请求
    【SpringMVC】SpringMVC系列1之HelloWorld
    【持续集成】[Jenkins]Job中如何传递自定义变量
    【持续集成】使用Jenkins实现多平台并行集成
    【云计算】Netflix 开源持续交付平台 Spinnaker
    【Other】推荐点好听的钢琴曲
  • 原文地址:https://www.cnblogs.com/duanjiapingjy/p/9444483.html
Copyright © 2020-2023  润新知