栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

ThreadLocal原理详解——原来ThreadLocal是这和强大的存在

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

ThreadLocal原理详解——原来ThreadLocal是这和强大的存在

ThreadLocal 定义

为每一个线程提供变量的副本,实现了线程的隔离,也可以保证线程的安全性。

和ThreadLocal相关类
  • ThreadLocal内部类ThreadLocalMap
  • ThreadLocalMap.Entry ThreadLocalMap内部类
  • Thread类

ThreadLocal是一个带泛型的类

public class ThreadLocal {}
源码分析

Android中最典型用到ThreadLocal地方在Looper里

public final class Looper {
    static final ThreadLocal sThreadLocal = new ThreadLocal();
    public static void loop() {
		final Looper me = myLooper();
	}
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }
}

sThreadLocal.get();源码解析

//泛型T为Looper,我们都会把T 替换成Looper
public class ThreadLocal {
	public Looper get() {
	    Thread t = Thread.currentThread();
	    //第一步: 通过getMap(t)获取一个ThreadLocalMap
	    ThreadLocalMap map = getMap(t);
	    //第一次进来这个map肯定为null
	    if (map != null) {
	    	//ThreadLocalMap.getEntry,获取缓存
	        ThreadLocalMap.Entry e = map.getEntry(this);
	        if (e != null) {
	            @SuppressWarnings("unchecked")
	            Looper result = (Looper)e.value;
	            return result;
	        }
	    }
	    //第三步 创建一个Looper
	    return setInitialValue();
	}
	
	ThreadLocalMap getMap(Thread t) {
		//第二步: 返回的是当前线程里的一个成员变量ThreadLocalMap threadLocals
	    return t.threadLocals;
	}
	
    private Looper setInitialValue() {
    	//第四步:通过initialValue()api得到了一个Looper 而initialValue()方法直接return 了一个null
    	//所这在没有做调用其它api的情况下ThreadLocal.get()方法获取的值为null
        Looper value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
        	//第五步: 创建ThreadLocalMap ,将Thread 里的成员变量threadLocals 附值
        	//threadLocals  = new ThreadLocalMap(this, firstValue);this为ThreadLoca, firstValue第一次为null
        	//这个时候当前线程的threadLocals就不为null了
            createMap(t, value);
        return value;
    }
    
    protected Looper initialValue() {
        return null;
    }
    
    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }
}

class Thread implements Runnable {
    ThreadLocal.ThreadLocalMap threadLocals = null;
}

//再来分析Looper里是怎么将sThreadLocal里设置值的

public final class Looper {
    static final ThreadLocal sThreadLocal = new ThreadLocal();
    
    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("only one Looper may be created per thread");
        }
        //第六步: 调用sThreadLocal.set方法将新创建的Looper给设置进去
        sThreadLocal.set(new Looper(quitAllowed));
    }
	
	//第九步:当set完值的时候再去get这就完全不一样了。
	public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }
    
	public Looper get() {
	    Thread t = Thread.currentThread();
	    //以当前线程为key去找值,获取的是当前线程的成员变量threadLocals,这个时候也不为null。且是每个Thread类独有的
	    ThreadLocalMap map = getMap(t);
		//这个时候map不为null了,已经有值了
	    if (map != null) {
	   		//第十步:当set完值的时候再去get这就完全不一样了。
	    	//ThreadLocalMap.getEntry,获取缓存 ThreadLocalMap其实相当于一个这样的HashMap
	    	//ThreadLocalMap.Entry 是一个WeakReference>
	    	//ThreadLocalMap里有个成功变量Entry[] table他会保存很多Entry 
	    	//每个ThreadLocalMap.Entry又执有了不同的ThreadLocal 和泛型T(Looper)类
	        ThreadLocalMap.Entry e = map.getEntry(this);
	        if (e != null) {
	            @SuppressWarnings("unchecked")
	            Looper result = (Looper)e.value;
	            return result;
	        }
	    }
	    //第三步 创建一个Looper
	    return setInitialValue();
	}
}

public class ThreadLocal {
    public void set(Looper value) {
        Thread t = Thread.currentThread();
        //第七步: 通过getMap获取当前线程的ThreadLocalMap ,如果在set之前什么没有调用ThreadLocal里的get方法那么这个map就为null
        //如果在set之前调用了get方法,那么这个map就不为null
        ThreadLocalMap map = getMap(t);
        if (map != null)
       		//第八步: 将传进来的Looper给设置进来了,key为ThreadLocal也主是Looper里的成功变量sThreadLocal  valus为创建的Looper
            map.set(this, value);
        else
        	//第五步: 创建ThreadLocalMap ,将Thread 里的成员变量threadLocals 附值
        	//threadLocals  = new ThreadLocalMap(this, firstValue);this为ThreadLocal, firstValue这个时候为value 不为null了
        	//这个时候当前线程的threadLocals就不为null了
            createMap(t, value);
    }
}
总结

1:每一个Thread都执有一个ThreadLocalMap变量threadLocals 他是通过ThreadLocal的createMap()方法创建

void createMap(Thread t, T firstValue) {
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}

2:ThreadLocalMap是ThreadLocal的一个内部类,他相当于一个HashMap,以ThreadLocal为Key,所以这里可以保证每一个ThreadLocal只能有一个值
3:而每一个Thread都执有一个ThreadLocalMap变量所以每一个线程里只要传入的ThreadLocal不变获取到的值也是唯一的。
4:ThreadLocalMap里有一个内部类 Entry
5:Entry这个类他会执行一个ThreadLocal和传进来的Object
6:ThreadLoca.get()先是获取本线程的一个ThreadLocalMap,然后通过ThreadLocalMap的getEntry方法找到值

示例

public class ThreadLocalTest {
	
	public static void main (String [] args) {

   		 ThreadLocal threadLocal = new ThreadLocal() {
    		    @Override
    		    protected Integer initialValue() {
      	     	 	return 1;
     		   }
 		   };
        new Thread(() -> {
            Integer integer = threadLocal.get();
            threadLocal.set(integer + 4);
            System.out.println("threadLocal1111: " + threadLocal.get());
        }).start();
        
        new Thread(() -> {
            System.out.println("threadLocal22222: " + threadLocal.get());
        }).start();

        new Thread(() -> {
        	System.out.println("threadLocal33333 before: " + threadLocal.get());
            threadLocal.set(9);
            System.out.println("threadLocal33333 after :" + threadLocal.get());
        }).start();
	}
	日志输出如下:
	System.out: threadLocal1111: 5
	System.out: threadLocal22222: 1
	System.out: threadLocal33333 before: 1
	System.out: threadLocal33333 after :9
	每一个线程 threadLocal都是不同的,他们也是隔离的,在一个线程设置值对其它线程是没有影响的
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/336949.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号