Heim  >  Artikel  >  Java  >  Java-Thread-Variable ThreadLocal-Quellcode-Analyse

Java-Thread-Variable ThreadLocal-Quellcode-Analyse

王林
王林nach vorne
2023-05-25 21:01:26811Durchsuche

1.ThreadLokale Thread-Variablen sind an den aktuellen Thread gebunden und speichern nur die Variablen des aktuellen Threads. Sie sind von anderen Threads isoliert und können nicht auf die darin enthaltenen Daten zugreifen.

2. ThreadLocal wird in Looper verwendet und ein Looper wird in ThreadLocal erstellt und gespeichert.

//这里用到了泛型,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));
}

Sehen Sie sich an, wie die Methode sThreadLocal.set() Daten speichert.

Erst den aktuellen Thread abrufen, dann die ThreadLocalMap-Mitgliedsvariable des Threads abrufen und sie dann in dieser Map speichern.

key ist das erstellte ThreadLocal-Objekt und value ist der übergebene Wert.

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

1) Speichern Sie die Daten, wenn die Karte nicht leer ist. Nehmen Sie den ersten Zweig des obigen if-Urteils. Diese Speichermethode ähnelt HashMap

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();
}

2) Speichern Sie die Daten, wenn die Karte leer ist. Erstellen Sie dann eine ThreadLocalMap und weisen Sie sie dem aktuellen Thread t zu.

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

3. Schauen wir uns an, wie ThreadLocal seinen Wert erhält.

Rufen Sie außerdem zuerst den aktuellen Thread t und dann seine Mitgliedsvariable ThreadLocalMap über t ab.

 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);
}

1) Wenn die Karte nicht leer ist, holen Sie sich den Wert aus der Karte.

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();
}
//如果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);
    }
}

2) Wenn die erhaltene Karte beim Abrufen leer ist, muss sie zu diesem Zeitpunkt initialisiert werden

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;
}
//如果map为空,则调用这个方法,initialValue由用户去实现。
private T setInitialValue() {
    T value = initialValue();
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
    return value;
}

ThreadLocalMap wird zum Speichern von ThreadLocal-Daten verwendet. Und dieses ThreadLocalMap-Objekt wird über

vom aktuellen Thread abgerufen und vom aktuellen Thread abgerufen. Das Design von ThreadLocalMap realisiert die Isolierung von Daten zwischen verschiedenen Threads und speichert nur die Daten des entsprechenden Threads.

Das ThreadLocal-Objekt selbst wird als Schlüssel zum Speichern von Daten in ThreadLocalMap verwendet. map.set(this, value);

Wenn Sie mehr Daten in ThreadLocalMap speichern möchten, müssen Sie mehrere Objekte erstellen.

Das obige ist der detaillierte Inhalt vonJava-Thread-Variable ThreadLocal-Quellcode-Analyse. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:yisu.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen