// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . // ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· // ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ // ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ // ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ // Magicbane Emulator Project © 2013 - 2022 // www.magicbane.com package engine.pooling; import org.pmw.tinylog.Logger; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.atomic.AtomicInteger; public abstract class LinkedObjectPool { private final LinkedBlockingQueue pool; private final AtomicInteger poolSize; /** * Constructor that allows the caller to specify initial array size and * percent of prefill. * * @param size - initial size for the containing array (pool) */ public LinkedObjectPool(int size) { this.pool = new LinkedBlockingQueue<>(); this.poolSize = new AtomicInteger(); } /** * Default Constructor that uses default initial Array size and percent * prefill values */ public LinkedObjectPool() { this(0); } /** * Forces pool to add numberOfObjects to the pool. This may cause * internal ArrayList to resize. * * @param numberOfObjects */ public void fill(int numberOfObjects) { for (int i = 0; i < numberOfObjects; ++i) this.makeAndAdd(); } /** * Forces subclasses to implement factory routine for object creation. */ protected abstract T makeNewObject(); /** * Forces subclasses to implement a way to reset object to a reusable state. */ protected abstract void resetObject(T obj); /** * Generic Get routine. If the pool is empty, then one (or more) of T type * objects will be created. If more than one T is created, then they will be * put into the pool. One T will always be created and returned. */ public T get() { T obj = pool.poll(); if (obj == null) { //Oops pool is empty.. make a new obj obj = this.makeNewObject(); } else { poolSize.decrementAndGet(); } return obj; } /** * Generic put routine. If the current pool size is below threshold, this * object will be pooled, otherwise it will be NULL'ed and scheduled for * Garbage Collection * * @param obj */ public void put(T obj) { //Logger.debug("Objectpool.put(). Pool size: " + pool.size()); this.resetObject(obj); this.poolSize.incrementAndGet(); this.pool.add(obj); } /** * Helper method. Attempts to create and add a new T object. If this * fails, an error is logged. */ protected final void makeAndAdd() { T obj = this.makeNewObject(); if (obj == null) { Logger.error("Pooling failure: Object creation failed."); } else { this.put(obj); } } /** * @return the current size of the pool, not the maximum capacity of the * Array holding the pool. */ public final int getPoolSize() { return this.poolSize.get(); } /** * Culls the pool and removes half of the stored objects. Removed objects * are NULL'ed and scheduled form Garbage Collection. * * @return the number of Objects removed from the pool. */ public int cullHalf() { int full, half; full = this.getPoolSize(); if (full < 1) { return full; } half = (full / 2); for (int i = 0; i < (full / 2); ++i) { T obj = this.pool.poll(); obj = null; // Null out for GC } return half; } protected void handlePoolExhaustion() { //Not needed in this implementation } }