博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[JAVA学习笔记-96]ThreadLocal
阅读量:4098 次
发布时间:2019-05-25

本文共 2895 字,大约阅读时间需要 9 分钟。

综述:
ThreadLocal可以理解为一个对象容器,这个容器为每个访问该容器的线程,封装了一个只对当前线程可见的对象。
也就是说,当多个线程共用一段代码时(例如同一个runnable对象分配给多个线程运行),ThreadLocal封装的对象
将会是线程安全的,只是访问的时候,需要用到set、get、remove、initValue等方法,否则,这些对象将会是多线程共享的,
是非线程安全的。
实现方法:
在Thread类中实现了一个 threadLocalMap<ThreadLocal key,T value>,执行ThreadLocal.set(T value)时,实质是获得当前Thread的这个 threadLocalMap ,将ThreadLocal对象作为Key(实质
是将该对象的HashCode作为Key)计算出下标(threadLocalMap是一个Entry[]),将指定的值存入数组中下标对应的位置。
    在执行 ThreadLocal.get 时,再次获取当前Thread的 threadLocalMap,通过 ThreadLocal 对象作为key索引到保存的value,并返回。
【1、ThreadLocal 的 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);  /*如果当前线程没有创建这个map,则创建一个。*/    }
【2、ThreadLocal 的 getMap方法:】
ThreadLocalMap getMap(Thread t) {        return t.threadLocals;    }
【3、ThreadLocal 的 createMap 方法:】
void createMap(Thread t, T firstValue) {        t.threadLocals = new ThreadLocalMap(this, firstValue);    }
【4、ThreadLocal.ThreadLocalMap 的构造方法:】
ThreadLocalMap(ThreadLocal firstKey, Object firstValue) {		table = new Entry[INITIAL_CAPACITY];		int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);  /*使用hashcode计算得到下标*/		table[i] = new Entry(firstKey, firstValue);		size = 1;		setThreshold(INITIAL_CAPACITY);	}		private Entry[] table;		static class Entry extends WeakReference
{ /*注意这里的 WeakReference*/ /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal k, Object v) { /*构造函数*/ super(k); value = v; } }
应用场景:
1、 web request handler
例如httpserver的hanler,向server注册一个GEThandler,每条http的GET请求都会调用此handler(假设只有一个handler对象,one thread per request),当并发的时候,handler中的
某些field会被多线程共享,且他们的值需要相互隔离(线程间不关心各自对这些field的修改),此时如果要线程安全,需要用ThreadLocal包装这些field。
2、 Reactor模式下的Accepter
多个连接并发的时候,Accepter可能需要用ThreadLocal隔离一些field,如果只有一个Accepter对象,而不是 new Thread(new Handler()).start(),那么可能需要用到ThreadLocal。
实例:
public class Task implements Runnable{	private static AtomicInteger num = new AtomicInteger(0);		private ThreadLocal
id = new ThreadLocal
(); @Override public void run() { // TODO Auto-generated method stub id.set(num.incrementAndGet()); /*每个线程从AtomicInteger返回一个唯一的值*/ System.out.println("id="+id.get()); /*每个线程的id值都是唯一的,并且相互之间感知不到,也不需要同步,因为此value实际上是Thread的local variable*/ } }
总结:
1、ThreadLocals are even more expensive than globals but they are certainly much better scoped.
2、ThreadLocal is for storing per-thread state past the execution scope of a method. 
3、Another option is using synchronized to manage access to a shared member variable. 
4、ThreadLocal,个人理解的应用场景为,当某个field为多线程共用,而field的值仅对各自线程有意义时,才用ThreadLocal包装隔离。
   如果这个共用的field的值,对所有的线程都有意义,例如A线程修改了它,而B线程需要用到这个修改后的值,那么需要用 synchronized 或者用Atomicxxx族的对象来进行同步;
   如果A线程修改的值,B线程并不关心,B线程只是与A线程共享了一段code而已,那么ThreadLocal可以用上。
   通常情况下,尽量使用local variables在性能上更好。

转载地址:http://ivhii.baihongyu.com/

你可能感兴趣的文章
JavaScript实现页面无刷新让时间走动
查看>>
CSS实例:Tab选项卡效果
查看>>
前端设计之特效表单
查看>>
前端设计之CSS布局:上中下三栏自适应高度CSS布局
查看>>
Java的时间操作玩法实例若干
查看>>
JavaScript:时间日期格式验证大全
查看>>
XML工具代码:SAX从String字符串XML内获取指定节点或属性的值
查看>>
时间日期:获取两个日期相差几天
查看>>
责任链模式 Chain of Responsibility
查看>>
高并发与大数据解决方案概述
查看>>
解决SimpleDateFormat线程安全问题NumberFormatException: multiple points
查看>>
MySQL数据库存储引擎简介
查看>>
处理Maven本地仓库.lastUpdated文件
查看>>
Java并发编程1-线程池
查看>>
CentOS7,玩转samba服务,基于身份验证的共享
查看>>
计算机网络-网络协议模型
查看>>
计算机网络-OSI各层概述
查看>>
Java--String/StringBuffer/StringBuilder区别
查看>>
mySQL--深入理解事务隔离级别
查看>>
分布式之redis复习精讲
查看>>