Rumah  >  Artikel  >  Java  >  Analisis kod sumber ThreadLocal pembolehubah benang Java

Analisis kod sumber ThreadLocal pembolehubah benang Java

王林
王林ke hadapan
2023-05-25 21:01:26855semak imbas

1. Pembolehubah utas ThreadLocal terikat pada utas semasa dan hanya menyimpan pembolehubah utas semasa Mereka diasingkan daripada utas lain dan tidak boleh mengakses data di dalamnya.

2. ThreadLocal digunakan dalam Looper, dan Looper dicipta dan disimpan dalam ThreadLocal.

//这里用到了泛型,ThreadLocal中只保存Looper对象。
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static void prepare(boolean quitAllowed) {
    if (sThreadLocal.get() != null) { //保证Looper只被创建一次。
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    sThreadLocal.set(new Looper(quitAllowed));
}

Lihat cara kaedah sThreadLocal.set() menyimpan data.

Mula-mula dapatkan utas semasa, kemudian dapatkan pembolehubah ahli ThreadLocalMap bagi utas itu, kemudian simpannya ke peta ini

kunci ialah objek ThreadLocal yang dibuat dan nilai ialah nilai yang dihantar .

  public void set(T value) {
        //拿到当前线程
        Thread t = Thread.currentThread();
        //得到一个map
        ThreadLocalMap map = getMap(t);
        if (map != null){
        // 这个map是以当前对象为key的,这个this就是 ThreadLocal的实例 sThreadLocal
            map.set(this, value);
        }else{
            createMap(t, value);
        }
    }
rrree

1) Simpan data jika peta tidak kosong. Ambil cabang pertama penghakiman if di atas. Kaedah storan ini serupa dengan HashMap

//getMap 是从Thread中拿到了一个threadLocals变量,是ThreadLocal.ThreadLocalMap 的实例。
//保存的数据也是存在了这个map中,这也就是为什么ThreadLocal是和线程绑定的,对其他线程来说是隔离的原因所在。
ThreadLocalMap getMap(Thread t) {
      return t.threadLocals;
}

2) Simpan data jika peta kosong. Kemudian buat ThreadLocalMap dan tetapkan ia kepada benang semasa t.

private void set(ThreadLocal<?> key, Object value) {
      Entry[] tab = table;
      int len = tab.length;
      // 计算出key在集合中的索引,index
      int i = key.threadLocalHashCode & (len-1);
       //开始遍历整个数组,
       //取出索引为i的Entry,如果不为空,取出下一个,进行遍历
        for (Entry e = tab[i];
               e != null;
               e = tab[i = nextIndex(i, len)]) {
              ThreadLocal<?> k = e.get();
              //如果取出的k和传进来的key一致,则把新的值存起来。
              if (k == key) {
                  e.value = value;
                  return;
              }
              //直到取出最有一个,k==null则进行存储。
              if (k == null) {
                  replaceStaleEntry(key, value, i);
                  return;
              }
          }
          //如果索引i的位置,没有Entry,则把传进来的key和value保存在这个位置。
          tab[i] = new Entry(key, value);
          int sz = ++size;
          //如果大于阈值了,则进行扩容
          if (!cleanSomeSlots(i, sz) && sz >= threshold)
              rehash();
}
rrree

3. Mari lihat bagaimana ThreadLocal mendapat nilainya.

juga mula-mula mendapat utas semasa t, dan kemudian mendapatkan pembolehubah ahlinya ThreadLocalMap melalui t.

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

1) Jika peta tidak kosong, dapatkan nilai daripada peta.

 ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
    //创建一个大小为16的数组
    table = new Entry[INITIAL_CAPACITY];
    //计算得到的i是数组的角标。可以参考hashMap源码分析
    int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
    //赋值,保存数据
    table[i] = new Entry(firstKey, firstValue);
    size = 1;
    //扩容的阈值
    setThreshold(INITIAL_CAPACITY);
}
public T get() {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    //如果map不为空,则从map中取值
    if (map != null) {
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
    //如果map为空
    return setInitialValue();
}

2) Jika peta yang diperoleh kosong semasa mendapat, anda perlu memulakannya pada masa ini

//如果map不为空
 private Entry getEntry(ThreadLocal<?> key) {
    //拿到key对应的索引
    int i = key.threadLocalHashCode & (table.length - 1);
    //从数组中拿到Entry
    Entry e = table[i];
    if (e != null && e.get() == key){如果key一样直接返回
        return e;
    }else{//如果不一致则开始遍历
         return getEntryAfterMiss(key, i, e);
    }
}
private Entry getEntryAfterMiss(ThreadLocal<?> key, int i, Entry e) {
		Entry[] tab = table;
		int len = tab.length;
		while (e != null) {
			ThreadLocal<?> k = e.get();
			if (k == key)
				return e;
			if (k == null)
				expungeStaleEntry(i);
			else
				i = nextIndex(i, len);
			e = tab[i];
		}
		return null;
}

ThreadLocalMap digunakan untuk menyimpan data ThreadLocal. Objek ThreadLocalMap ini diperoleh daripada utas semasa melalui

dan diperoleh daripada utas semasa. Reka bentuk ThreadLocalMap menyedari pengasingan data antara benang yang berbeza dan hanya menyimpan data benang yang sepadan.

Objek ThreadLocal itu sendiri digunakan sebagai kunci untuk menyimpan data dalam ThreadLocalMap. map.set(this, value);

Jika anda ingin menyimpan lebih banyak data dalam ThreadLocalMap, anda perlu mencipta berbilang objek.

Atas ialah kandungan terperinci Analisis kod sumber ThreadLocal pembolehubah benang Java. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:yisu.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam