Die schwache Referenz von JAVA hat die für jeden Thread zugewiesene Instanz wiederverwendet

Schwache Referenz

In JAVA verschwinden Instanzen, auf die andere nicht mehr verweisen, wenn eine Garbage Collection (GC) durchgeführt wird. Umgekehrt verschwindet die referenzierte Instanz nie. Schwach referenzierte Instanzen verschwinden jedoch in GC.

Die Referenz, die ich normalerweise benutze, ist eine starke Referenz. string s = "String"; Solange die Methode, die s wie oben deklariert, fortgesetzt wird, bleibt die "Zeichenfolge" beispielsweise im Speicher.

Unten ist eine schwache Referenz weakreference<string> wrs = new weakreference<string>("String"); Die "Zeichenkette" kann mit der get-Methode von wrs erhalten werden. Da wrs selbst eine starke Referenz ist, bleibt es im Speicher, solange die Methode fortgesetzt wird. Die in wrs eingegebene "Zeichenkette" ist jedoch eine schwache Referenz. Wenn Sie beispielsweise GC unmittelbar nach dem Deklarieren von wrs ausführen, verschwindet die "Zeichenfolge" aus dem Speicher und kann nicht abgerufen werden.

Schwache Referenzkarte

WeakHashMap verweist schwach auf die verschlüsselte Instanz. Wenn die Referenz der Schlüsselinstanz von einer anderen als WeakHashMap verschwindet und GC ausgeführt wird, verschwindet jeder Schlüsseleintrag von WeakHashMap.

Verwendung einer schwachen Referenz

Es ist eine schwache Referenz, die nicht sehr nützlich ist. Ich habe es in einer Kombination aus einer Instanz, die verschwindet, und einer Instanz verwendet, die ich nicht löschen möchte **.

Verwenden Sie für jeden Thread eine eindeutige Instanz erneut

Wenn Sie für jeden Thread eine eindeutige Instanz garantieren möchten, verwenden Sie ThreadLocal. Wenn bei ThreadLocal die Instanz nur von diesem Thread referenziert wird, verschwindet die Instanz, wenn der Thread verschwindet. Wenn Sie also möchten, dass andere Threads eine Instanz wiederverwenden, auf die kein Thread mehr verweist, können Sie eine schwache Referenzzuordnung verwenden.

Beim Sichern einer eindeutigen Instanz für jeden Thread kann die gesicherte Instanz beim Verschwinden dieses Threads von dem Thread wiederverwendet werden, der eine neue Instanz sichern möchte.

RecyclePool.java


import java.util.ArrayList;
import java.util.List;
import java.util.WeakHashMap;

/**
 * Keep element of each thread, and another thread can reuse element when that thread disappears.
 *
 * @param <E> The element type of this pool
 */
public class RecyclePool<E> {

  private final List<E> elementList = new ArrayList<>();
  private final WeakHashMap<Thread, E> weakElementMap = new WeakHashMap<>();

  /**
   * Appends the specified element to the this pool.
   *
   * @param element element to be appended to this pool
   */
  public void add(E element) {
    synchronized (elementList) {
      elementList.add(element);
      weakElementMap.put(Thread.currentThread(), element);
    }
  }

  /**
   * Returns the number of elements in this pool.
   *
   * @return the number of elements in this pool
   */
  public int size() {
    return elementList.size();
  }

  /**
   * Returns the element keeping by current thread. if current thread does not keep element then,
   * keeping and returning the element kept by disappear thread. or {@code null} if all elements of
   * this pool are kept by other threads.
   *
   * @return the element kept by current thread
   */
  public E get() {
    Thread currentThread = Thread.currentThread();
    E myElement = weakElementMap.get(currentThread);
    if (myElement != null) {
      return myElement;
    }
    synchronized (elementList) {
      if (elementList.size() <= weakElementMap.size()) {
        return null;
      }
      for (E element : elementList) {
        if (!weakElementMap.containsValue(element)) {
          weakElementMap.put(currentThread, element);
          myElement = element;
          break;
        }
      }
    }
    return myElement;
  }

  /**
   * Execute garbage collection for reusing elements kept by the thread to be disappear.
   */
  public void refresh() {
    for (int retry = 0; retry <= 10; retry++) {
      System.gc();
      if (elementList.size() > weakElementMap.size()) {
        return;
      }
      try {
        Thread.sleep(1);
      } catch (InterruptedException e) {
        ;
      }
    }
  }

}

Legen Sie die Instanz fest, die Sie für jeden Thread mit der Methode add sichern möchten, und rufen Sie sie mit der Methode get ab. Selbst wenn ein anderer Thread als der hinzugefügte Thread abgerufen wird, kann die Instanz nicht erfasst werden. Wenn der hinzugefügte Thread jedoch bereits im GC verschwunden ist, kann er von einem anderen Thread und nicht von einem anderen Thread erfasst werden.

Auch wenn der Thread nicht mehr aktiv ist und keine Referenzen mehr vorhanden sind, bleibt die Instanz ohne GC reserviert. Ich habe es manuell mit der Aktualisierungsmethode GC erstellt und die Freigabe erzwungen.

Diese Quelle wird tatsächlich in [numatrix] verwendet (https://qiita.com/ReijiHata/items/37713d3dfc32ee44ac68). Da numatrix ein eindeutiges NumatrixNumberGenerator Limit für jeden Thread hat, werden Threads nacheinander erstellt. Es bestand die Sorge, dass die Anzahl der Numatlix-Zahlengeneratoren die Obergrenze erreichen würde, wenn sie so verwendet würden, als ob sie hergestellt würden. Verwenden Sie RecyclePool, um NumatlixNumberGenerator für jeden Thread zu sichern, und verwenden Sie NumatlixNumberGenerator, der nicht mehr verwendet wird. Wiederverwendung für einen anderen Thread.

Recommended Posts

Die schwache Referenz von JAVA hat die für jeden Thread zugewiesene Instanz wiederverwendet
Links für jede Version (japanische Version) der Java SE-API
Zusammenfassung der Methoden zum Lesen von Dateien für jedes Java-Dateiformat
Java-Thread sicher für Sie
[Für Anfänger] Zusammenfassung des Java-Konstruktors
[Java] Referenz / Update von Active Directory
Kotlin-Generika für Java-Entwickler
Implementierung der Klonmethode für Java Record
Liste der Download-Ziele für Oracle Java
Funktionen des Spring Frameworks für Java-Entwickler