ThreadLocal
什么是ThreadLocal?
threadLocal是一个线程内部的存储类,可以在指定的线程内存储数据,各线程在threadLocal中存储的数据不会相互干扰。ThreadLocal可以通过set和get方法存储数据和获取数据。
多个线程可以共用一个threadLocal,用来存储线程中的数据,各个线程在取数据的时候不会相互干扰。
ThreadLocla和synchronize的区别
ThreadLocal原理是开辟一块独立的内存空间;sychronize原理是锁住当前线程,让其他线程等待同步锁资源
threadLocal存储数据的简单测试:
public class ThreadLocalTest {
private ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
public ThreadLocalTest() {
threadLocal.set(88);
Logger.D("threadName: " + Thread.currentThread().getName() + " threadLocal value: " + threadLocal.get());
}
public void createThread1() {
new Thread(new Runnable() { @Override public void run() { threadLocal.set(10);
Logger.D("threadName: " + Thread.currentThread().getName() + " threadLocal value: " + threadLocal.get());
} }).start(); } }
//调用后的日志结果
D/---iCat--->: threadName: main threadLocal value: 88
D/---iCat--->: threadName: Thread-3 threadLocal value: 10
问题:
1. ThreadLocal为什么能够存储数据?
因为ThreadLocal内部维护了一个数组
2. ThreadLocal在取值的时候为什么不用传递key?
在存值的时候,会将当前的theadLocal的hashCode与数组的长度进行位运算得到key(数组存值的下标)
3. 各线程在ThreadLocal中存储数据为什么可以做到不相互干扰,保证线程安全
不同线程在使用同一个ThreadLocal存储数据的时候,会创建各自的ThreadLocalMap,threadLocalMap中维护着一个数组,也就是说:不同的线程使用同一个ThreadLocal存储数据时使用的是各自独立的内存。
4.另外在ThreadLocla中使用到了AtomicInterger,使用它的作用
自己的总结
不同线程之间使用同一个ThreadLocal对象存值:不同线程持有着不同的ThradLocalMap对象,每一个ThreadLocalMap维护着一个Entry数组,也就是可以理解为:一个线程维护着一个Entry数组,而ThreadLocal在创建的时候初始化了threadLocalHashCode,所以不同的线程在各自维护的数组中存储数据的key是相同的。
同一个线程的不同的ThreadLcoal共享同一个ThreadLocalMap的Entry数组,在存值的时候通过当前ThreadLocal的hashCode与Entry数组长度减1进行位运算计算出一个数组的存值下标,也就是说:同一个线程在使用不同的ThreadLocal存值的时候是共享同一个数组,存储于同一个数组的不同位置。
ThreadLcoal的原理:
ThreadLocal的静态内部类ThreadLocalMap为每个Thread都维护了一个数组table,ThreadLocal确定了一个数组下标,而这个下标就是value存储的对应位置
ThreadLocal特性
ThreadLocal和Synchronized都是为了解决多线程中相同变量的访问冲突问题,不同的点是
- Synchronized是通过线程等待,牺牲时间来解决访问冲突
- ThreadLocal是通过每个线程单独一份存储空间,牺牲空间来解决冲突,并且相比于Synchronized,ThreadLocal具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问到想要的值。
同一个线程数据共享,不同线程数据隔离;
应用:
正因为ThreadLocal的线程隔离特性,使他的应用场景相对来说更为特殊一些。在android中Looper、ActivityThread以及AMS中都用到了ThreadLocal。当某些数据是以线程为作用域并且不同线程具有不同的数据副本的时候,就可以考虑采用ThreadLocal。
总结:
1. 对于某一ThreadLocal来讲,他的索引值i是确定的,在不同线程之间访问时访问的是不同的table数组的同一位置即都为table[i],只不过这个不同线程之间的table是独立的。
2. 对于同一线程的不同ThreadLocal来讲,这些ThreadLocal实例共享一个table数组,然后每个ThreadLocal实例在table中的索引i是不同的。
注意:在使用完毕ThreadLocal之后,请调用remove方法释放资源,防止内存泄漏
源码我这里就不贴出分析了,自行去看或者参看下边这边文章