扬中网站推广报价,唐山市城市建设档案馆网站,鹰潭网站制作,学网站开发去哪学1 概述
ThreadLocal用于在当前线程中存储数据#xff0c;由于存储的数据只能在当前线程内使用#xff0c;所以自然是线程安全的。 Handler体系中#xff0c;Looper只会存在一个实例#xff0c;且只在当前线程使用#xff0c;所以使用ThreadLocal进行存储。
2 存储原理
…1 概述
ThreadLocal用于在当前线程中存储数据由于存储的数据只能在当前线程内使用所以自然是线程安全的。 Handler体系中Looper只会存在一个实例且只在当前线程使用所以使用ThreadLocal进行存储。
2 存储原理
frameworks/base/core/java/android/os/Looper.java
static final ThreadLocalLooper sThreadLocal new ThreadLocalLooper();private static void prepare(boolean quitAllowed) {if (sThreadLocal.get() ! null) {throw new RuntimeException(Only one Looper may be created per thread);}sThreadLocal.set(new Looper(quitAllowed));
}public static Nullable Looper myLooper() {return sThreadLocal.get();
}Looper类中使用ThreadLocal来存储Looper对象在调用prepare方法的时候判断ThreadLocal对象中是否包含Looper对象如果包含说明重复调用了prepare会抛异常。调用myLooper的时候就从ThreadLocal对象中获取Looper对象。 从上面可以看出ThreadLocal类似于一个容器可以存储一个对象通过set方法将对象存储到ThreadLocal容器中通过get从ThreadLocal容器中获取对象。 首先看一下ThreadLocal的构造方法
public ThreadLocal() {
}是空参构造没有任何处理 接下来看ThreadLocal的set方法
public void set(T value) {Thread t Thread.currentThread();ThreadLocalMap map getMap(t);if (map ! null)map.set(this, value);elsecreateMap(t, value);
}首先获取当前Thread对象然后通过Thread对象获取ThreadLocalMap如果map为空则创建Map如果map不为空调用set方法则将ThreadLocal作为key元素作为value设置到map中 java/lang/ThreadLocal.java
ThreadLocalMap getMap(Thread t) {return t.threadLocals;
}java/lang/Thread.java
ThreadLocal.ThreadLocalMap threadLocals null;每一个Thread对象都持有一个ThreadLocalMap对象如果该对象没有创建的话就会调用set里面的createMap进行创建。 java/lang/ThreadLocal.java
void createMap(Thread t, T firstValue) {t.threadLocals new ThreadLocalMap(this, firstValue);
}初始化ThreadLocalMap传入参数为ThreadLocal对象和Object对象 java/lang/ThreadLocal.java
ThreadLocalMap(ThreadLocal? firstKey, Object firstValue) {table new Entry[INITIAL_CAPACITY];int i firstKey.threadLocalHashCode (INITIAL_CAPACITY - 1);table[i] new Entry(firstKey, firstValue);size 1;setThreshold(INITIAL_CAPACITY);
}ThreadLocalMap存储元素采用的是Entry数组初始容量为16跟HashMap方式类似采用2的指数次为数组长度进行hash。 ThreadLocalMap的set方法
private void set(ThreadLocal? key, Object value) {// We dont use a fast path as with get() because it is at// least as common to use set() to create new entries as// it is to replace existing ones, in which case, a fast// path would fail more often than not.Entry[] tab table;int len tab.length;int i key.threadLocalHashCode (len-1);for (Entry e tab[i];e ! null;e tab[i nextIndex(i, len)]) {// Android-changed: Use refersTo() (twice).// ThreadLocal? k e.get();// if (k key) { ... } if (k null) { ... }if (e.refersTo(key)) {e.value value;return;}if (e.refersTo(null)) {replaceStaleEntry(key, value, i);return;}}tab[i] new Entry(key, value);int sz size;if (!cleanSomeSlots(i, sz) sz threshold)rehash();
}采用hash算法使用ThreadLocal对象作为Key计算索引并存入value。 ThreadLocal的get方法
public T get() {Thread t Thread.currentThread();ThreadLocalMap map getMap(t);if (map ! null) {ThreadLocalMap.Entry e map.getEntry(this);if (e ! null) {SuppressWarnings(unchecked)T result (T)e.value;return result;}}return setInitialValue();
}首先获取Thread对象然后获取Thread对象中的ThreadLocalMap对象然后调用getEntry获取Entry对象并返回其value。
private Entry getEntry(ThreadLocal? key) {int i key.threadLocalHashCode (table.length - 1);Entry e table[i];// Android-changed: Use refersTo().if (e ! null e.refersTo(key))return e;elsereturn getEntryAfterMiss(key, i, e);
}也是通过hash算法算出索引后返回Entry对象
3 总结
ThreadLocal用于存储线程私有数据一个ThreadLocal对象可以存储一个数据ThreadLocal实现线程私有是因为存储数据时存储到Thread类中持有的ThreadLocalMap对象中的Entry数组中采用哈希算法进行存储key为ThreadLocal对象value为T类型由于不同的线程存储到的就是不同的Thread类的ThreadLocalMap中所以各个线程的ThreadLocalMap独立自然存储其中的ThreadLocal就是独立的同一个线程中多个ThreadLocal存储多个数据但存入的是同一个Thread对象的同一个ThreadLocalMap对象中所以一个线程对应一个Thread对象对应同一个ThreadLocalMap对象可以存储多个ThreadLocal数据