La faible référence de JAVA a réutilisé l'instance allouée pour chaque thread

Référence faible

Dans JAVA, les instances qui ne sont plus référencées par d'autres disparaissent lorsque le garbage collection (GC) est effectué. A l'inverse, l'instance référencée ne disparaît jamais. Mais les instances faiblement référencées disparaissent dans GC.

La référence que j'utilise habituellement est une référence forte. string s = "Chaîne"; Par exemple, tant que la méthode qui déclare s comme ci-dessus continue, la "chaîne" restera en mémoire.

Voici une référence faible weakreference<string> wrs = new weakreference<string>("Chaîne"); La "chaîne de caractères" peut être obtenue avec la méthode get de wrs. Puisque wrs lui-même est une référence forte, il reste en mémoire tant que la méthode continue. Cependant, la "chaîne de caractères" placée dans wrs est une référence faible. Par exemple, si vous exécutez GC immédiatement après avoir déclaré wrs, la "chaîne de caractères" disparaît de la mémoire et ne peut pas être récupérée.

Carte de référence faible

WeakHashMap fait faiblement référence à l'instance saisie. Si la référence de l'instance à clé disparaît d'une autre que WeakHashMap et que GC est effectuée, chaque entrée de clé disparaît de WeakHashMap.

Utilisation d'une référence faible

C'est une référence faible qui n'est pas très utile, Je l'ai utilisé dans une combinaison d'une instance qui disparaît et d'une instance que je ne veux pas effacer **.

Réutiliser une instance unique pour chaque thread

Si vous souhaitez garantir une instance unique pour chaque thread, utilisez ThreadLocal. Avec ThreadLocal, si l'instance n'est référencée que par ce thread, l'instance disparaît lorsque le thread disparaît. Ainsi, si vous souhaitez que d'autres threads réutilisent une instance qui n'est plus référencée par un thread, vous pouvez utiliser une carte de référence faible.

Lors de la sécurisation d'une instance unique pour chaque thread, lorsque ce thread disparaît, l'instance sécurisée peut être réutilisée par le thread qui souhaite sécuriser une nouvelle instance.

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

}

Définissez l'instance que vous souhaitez sécuriser pour chaque thread avec la méthode add et obtenez-la avec la méthode get. Même si un thread autre que le thread ajouté obtient, l'instance ne peut pas être acquise. Cependant, si le thread ajouté a déjà disparu dans le GC, il peut être acquis par un autre thread et ne peut pas être acquis par un autre thread.

Même si le thread n'est plus actif et aucune référence, l'instance reste réservée sans GC. Je l'ai fait manuellement GC avec la méthode de rafraîchissement et je l'ai forcé à être publié.

Cette source est en fait utilisée dans numatrix. Comme numatrix a une limite [NumatrixNumberGenerator] unique (https://github.com/ReijiHata/numatrix/blob/master/src/main/java/numatrix/NumatrixNumberGenerator.java) pour chaque thread, les threads sont créés les uns après les autres. On craignait que le nombre de NumatlixNumberGenerators n'atteigne la limite supérieure s'il était utilisé comme s'il était fabriqué. Utilisez RecyclePool pour sécuriser NumatlixNumberGenerator pour chaque thread et utilisez NumatlixNumberGenerator qui n'est plus utilisé. Réutilisation pour un autre thread.

Recommended Posts

La faible référence de JAVA a réutilisé l'instance allouée pour chaque thread
Liens pour chaque version (version japonaise) de l'API Java SE
Résumé des méthodes de lecture de fichiers pour chaque format de fichier Java
Java thread sans danger pour vous
[Pour les débutants] Résumé du constructeur java
[Java] Référence / mise à jour d'Active Directory
Génériques Kotlin pour les développeurs Java
Implémentation de la méthode de clonage pour Java Record
Liste des destinations de téléchargement pour Oracle Java
Fonctionnalités du framework Spring pour les développeurs Java