ThreadLocal详解

第一步:分析   ThreadLocal的源码

ThreadLocal有一个内部类ThreadLocalMap,这个类的实现占了整个ThreadLocal类源码的一多半。这个ThreadLocalMap的作用非常关键,它就是线程真正保存线程自己本地变量的容器。每一个线程都有自己的单独的一个ThreadLocalMap实例,

public T get() {
        //获取当前执行线程
        Thread t = Thread.currentThread();
        //取得当前线程的ThreadLocalMap实例
        ThreadLocalMap map = getMap(t);
        //如果map不为空,说明该线程已经有了一个ThreadLocalMap实例
        if (map != null) {
            //map中保存线程的所有的线程本地变量,我们要去查找当前线程本地变量
            ThreadLocalMap.Entry e = map.getEntry(this);
            //如果当前线程本地变量存在这个map中,则返回其对应的值
            if (e != null)
                return (T)e.value;
        }
        //如果map不存在或者map中不存在当前线程本地变量,返回初始值
        return setInitialValue();
    }

注意这里最后一步是调用了

InitialValue()方法来实现对本地变量的初始化
Thread对象都有一个ThreadLocalMap类型的属性threadLocals,这个属性是专门用于保存自己所有的线程本地变量的。这个属性在线程对象初始化的时候为null。所以对一个线程对象第一次使用线程本地变量的时候,需要对这个threadLocals属性进行初始化操作。
 getMap方法:

//直接返回线程对象的threadLocals属性
ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }
 setInitialValue方法:

private T setInitialValue() {
        //获取初始化值,initialValue 就是我们之前覆盖的方法
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        //如果map不为空,将初始化值放入到当前线程的ThreadLocalMap对象中
        if (map != null)
            map.set(this, value);
        else
            //当前线程第一次使用本地线程变量,需要对map进行初始化工作
            createMap(t, value);
        //返回初始化值
        return value;
    }
 我们再来看一下set方法

public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);

        if (map != null)
            map.set(this, value);
        //说明线程第一次使用线程本地变量(注意这里的第一次含义)
        else
            createMap(t, value);
    }
ThradLocal还有一个remove方法:
public void remove() {
         //获取当前线程的ThreadLocalMap对象
         ThreadLocalMap m = getMap(Thread.currentThread());
         //如果map不为空,则删除该本地变量的值
         if (m != null)
             m.remove(this);
     }

第二步:应用分析

package com.threadlocal;

import java.util.logging.Logger;
	
public class threadlocaldemo {
	private static Logger logger =Logger.getLogger("threadlocaldemo.class");
	private static int id=0;
	private static ThreadLocal<People> threadLocal =new ThreadLocal<People>() {
		protected People initialValue() {
			
			People people =new People();
			 people.setId(++id);
			return people;
		};
	};
	public static void main(String[] args) {
		logger.info("测试开始");
		for(int i=0;i<5;i++) {
			new Thread(new Runnable() {
				  public  void run() {
					  System.out.println("my name is :"+Thread.currentThread().getName()+"--"+threadLocal.get().getId());
				  };
			}).start();
		}
	}

}
结果:
五月 03, 2018 10:55:15 上午 com.threadlocal.threadlocaldemo main
信息: 测试开始
my name is :Thread-3--3
my name is :Thread-5--2
my name is :Thread-4--1
my name is :Thread-2--1
my name is :Thread-1--1

从结果可以清晰的看出 并没有实现线程间变量相互隔离的效果,分析

private static int id=0;
	private static ThreadLocal<People> threadLocal =new ThreadLocal<People>() {
		protected People initialValue() {
			
			People people =new People();
			 people.setId(++id);
			return people;
		};
	};

这种情况下的模型

情况二:
package com.threadlocal;

import java.util.logging.Logger;
	
public class threadlocaldemo {
	private static Logger logger =Logger.getLogger("threadlocaldemo.class");

	private static ThreadLocal<People> threadLocal =new ThreadLocal<People>() {
		protected People initialValue() {
			int id=0;
			People people =new People();
			 people.setId(++id);
			return people;
		};
	};
	public static void main(String[] args) {
		logger.info("测试开始");
		for(int i=0;i<5;i++) {
			new Thread(new Runnable() {
				  public  void run() {
					  System.out.println("my name is :"+Thread.currentThread().getName()+"--"+threadLocal.get().getId());
				  };
			}).start();
		}
	}

}

结果:

信息: 测试开始
my name is :Thread-5--1
my name is :Thread-1--1
my name is :Thread-3--1
my name is :Thread-4--1
my name is :Thread-2--1

模型:




猜你喜欢

转载自blog.csdn.net/yaoyaowudi123/article/details/80176619