org.xbib.io.pool.jdbc.util.Bag Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of connection-pool-jdbc Show documentation
Show all versions of connection-pool-jdbc Show documentation
JDBC connection pooling for Java 11+
The newest version!
package org.xbib.io.pool.jdbc.util;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.AbstractQueuedLongSynchronizer;
import java.util.concurrent.locks.LockSupport;
import java.util.logging.Logger;
import java.util.stream.Collectors;
/**
* This is a specialized concurrent bag that achieves superior performance
* to {@link java.util.concurrent.LinkedBlockingQueue} and
* {@link java.util.concurrent.LinkedTransferQueue} for the purposes of a
* connection pool. It uses {@link ThreadLocal} storage when possible to avoid
* locks, but resorts to scanning a common collection if there are no
* available items in the {@link ThreadLocal} list. Not-in-use items in the
* {@link ThreadLocal} lists can be "stolen" when the borrowing thread has none
* of its own. It is a "lock-less" implementation using a specialized
* {@link AbstractQueuedLongSynchronizer} to manage cross-thread signaling.
* Note that items that are "borrowed" from the bag are not actually
* removed from any collection, so garbage collection will not occur
* even if the reference is abandoned. Thus care must be taken to
* {@link Bag#requite(T)} borrowed objects otherwise a memory leak will result.
* Only the {@link Bag#remove(T)} method can completely remove an object.
*
* @param the templated type to store in the bag
*/
public class Bag implements AutoCloseable {
private static final Logger logger = Logger.getLogger(Bag.class.getName());
private final CopyOnWriteArrayList sharedList;
private final boolean weakThreadLocals;
private final ThreadLocal> threadList;
private final BagStateListener listener;
private final AtomicInteger waiters;
private volatile boolean closed;
private final SynchronousQueue handoffQueue;
private String lastMessage;
/**
* Construct a Bag with the specified listener.
*
* @param listener the IBagStateListener to attach to this bag
*/
public Bag(BagStateListener listener) {
this.listener = listener;
this.weakThreadLocals = useWeakThreadLocals();
this.handoffQueue = new SynchronousQueue<>(true);
this.waiters = new AtomicInteger();
this.sharedList = new CopyOnWriteArrayList<>();
if (weakThreadLocals) {
this.threadList = ThreadLocal.withInitial(() -> new ArrayList<>(16));
} else {
this.threadList = ThreadLocal.withInitial(() -> new FastList<>(BagEntry.class, 16));
}
}
public String getLastMessage() {
return lastMessage;
}
/**
* The method will borrow a BagEntry from the bag, blocking for the
* specified timeout if none are available.
*
* @param timeout how long to wait before giving up, in units of unit
* @param timeUnit a TimeUnit
determining how to interpret the timeout parameter
* @return a borrowed instance from the bag or null if a timeout occurs
* @throws InterruptedException if interrupted while waiting
*/
public T borrow(long timeout, final TimeUnit timeUnit) throws InterruptedException {
// Try the thread-local list first
final List