Weak reference of JAVA reused instance allocated for each thread

Weak reference

In JAVA, instances that are no longer referenced by others disappear when garbage collection (GC) is performed. Conversely, the referenced instance never disappears. But the weakly referenced instance disappears in GC.

The reference I usually use is a strong reference. string s = "String"; For example, as long as the method declaring s as above continues, the "string" will remain in memory.

Weak reference below weakreference<string> wrs = new weakreference<string>("String"); The "string" can be obtained with the get method of wrs. Since wrs itself is a strong reference, it remains in memory as long as the method continues. However, the "string" in wrs is a weak reference. For example, if you run GC immediately after declaring wrs, the "string" disappears from memory and cannot be retrieved.

Weak reference map

WeakHashMap weakly references the keyed instance. If the reference of the keyed instance disappears from other than WeakHashMap and GC is performed, each key entry disappears from WeakHashMap.

Use of weak references

It's a weak reference that's not very useful, I used it in combination with the instance that disappears and the instance that I don't want to erase **.

Reuse a unique instance for each thread

If you want to guarantee a unique instance for each thread, you can use ThreadLocal. With ThreadLocal, if the instance is only referenced by that thread, the instance disappears when the thread disappears. So, weak reference maps could be used when you want other threads to reuse instances that are no longer referenced by a thread.

While securing a unique instance for each thread, when that thread disappears, the secured instance can be reused by the thread that wants to secure a new 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) {
        ;
      }
    }
  }

}

Set the instance you want to secure for each thread with the add method, and get it with the get method. Even if a thread other than the added thread gets, the instance cannot be acquired. However, if the added thread has already disappeared in the GC, it can be acquired by another thread and cannot be acquired by another thread.

Even if the thread is no longer active & no references, the instance remains reserved without GC. The refresh method was used to manually perform GC and forcibly release it.

This source is actually used in numatrix. Since numatrix has a unique NumatrixNumberGenerator limit for each thread, threads are created one after another. There was a concern that the number of NumatlixNumberGenerators would reach the upper limit if used as if it were made. Use RecyclePool to secure NumatlixNumberGenerator for each thread, and use NumatlixNumberGenerator that is no longer used. Reusing for another thread.

Recommended Posts

Weak reference of JAVA reused instance allocated for each thread
Links for each version (Japanese version) of Java SE API
Summary of file reading method for each Java file format
Java thread safe for you
[Java] Summary of for statements
[For beginners] Summary of java constructor
[Java] Reference / update of Active Directory
Generics of Kotlin for Java developers
Implementation of clone method for Java Record
List of download destinations for oracle java
Features of spring framework for java developers