New concurrent connection container (moved away from LinkedBlockingQueue and LinkedTransferQueue).
parent
71ef0b6b8d
commit
522717f885
@ -0,0 +1,178 @@
|
||||
package com.zaxxer.hikari;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicStampedReference;
|
||||
import java.util.concurrent.locks.AbstractQueuedLongSynchronizer;
|
||||
|
||||
public class SpecializedConcurrentBag<T>
|
||||
{
|
||||
static final int NOT_IN_USE = 0;
|
||||
static final int IN_USE = 1;
|
||||
static final int REMOVED = -1;
|
||||
|
||||
private ConcurrentHashMap<T, AtomicStampedReference<T>> map;
|
||||
private Synchronizer synchronizer;
|
||||
|
||||
private ThreadLocal<LinkedList<AtomicStampedReference<T>>> threadList = new ThreadLocal<LinkedList<AtomicStampedReference<T>>>()
|
||||
{
|
||||
protected LinkedList<AtomicStampedReference<T>> initialValue()
|
||||
{
|
||||
return new LinkedList<>();
|
||||
}
|
||||
};
|
||||
|
||||
public SpecializedConcurrentBag()
|
||||
{
|
||||
map = new ConcurrentHashMap<>();
|
||||
synchronizer = new Synchronizer();
|
||||
}
|
||||
|
||||
public T poll(long timeout, TimeUnit timeUnit) throws InterruptedException
|
||||
{
|
||||
// Try the thread-local list first
|
||||
LinkedList<AtomicStampedReference<T>> list = threadList.get();
|
||||
while (!list.isEmpty())
|
||||
{
|
||||
AtomicStampedReference<T> stampedReference = list.removeLast();
|
||||
final T reference = stampedReference.getReference();
|
||||
if (stampedReference.compareAndSet(reference, reference, NOT_IN_USE, IN_USE))
|
||||
{
|
||||
return reference;
|
||||
}
|
||||
}
|
||||
|
||||
timeout = timeUnit.toNanos(timeout);
|
||||
do {
|
||||
final long start = System.nanoTime();
|
||||
for (AtomicStampedReference<T> stampedReference : map.values())
|
||||
{
|
||||
final T reference = stampedReference.getReference();
|
||||
if (stampedReference.compareAndSet(reference, reference, NOT_IN_USE, IN_USE))
|
||||
{
|
||||
return reference;
|
||||
}
|
||||
}
|
||||
|
||||
synchronizer.tryAcquireSharedNanos(1, timeout);
|
||||
|
||||
timeout -= (System.nanoTime() - start);
|
||||
} while (timeout > 0);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean offer(T value)
|
||||
{
|
||||
LinkedList<AtomicStampedReference<T>> list = threadList.get();
|
||||
AtomicStampedReference<T> stampedReference = map.get(value);
|
||||
if (stampedReference == null)
|
||||
{
|
||||
stampedReference = new AtomicStampedReference<T>(value, NOT_IN_USE);
|
||||
map.put(value, stampedReference);
|
||||
list.addLast(stampedReference);
|
||||
}
|
||||
else
|
||||
{
|
||||
final T reference = stampedReference.getReference();
|
||||
if (stampedReference.compareAndSet(reference, reference, IN_USE, NOT_IN_USE))
|
||||
{
|
||||
list.addLast(stampedReference);
|
||||
}
|
||||
}
|
||||
|
||||
synchronizer.releaseShared(1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void remove(T value)
|
||||
{
|
||||
AtomicStampedReference<T> stampedReference = map.get(value);
|
||||
if (stampedReference != null)
|
||||
{
|
||||
stampedReference.set(stampedReference.getReference(), REMOVED);
|
||||
map.remove(value);
|
||||
}
|
||||
}
|
||||
|
||||
public List<T> values(int state)
|
||||
{
|
||||
ArrayList<T> list = new ArrayList<>(map.size());
|
||||
for (AtomicStampedReference<T> stampedReference : map.values())
|
||||
{
|
||||
if (stampedReference.getStamp() == state)
|
||||
{
|
||||
list.add(stampedReference.getReference());
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
T checkout(T value)
|
||||
{
|
||||
AtomicStampedReference<T> stampedReference = map.get(value);
|
||||
if (stampedReference != null && stampedReference.compareAndSet(stampedReference.getReference(), stampedReference.getReference(), NOT_IN_USE, IN_USE))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
void checkin(T value)
|
||||
{
|
||||
AtomicStampedReference<T> stampedReference = map.get(value);
|
||||
if (stampedReference != null)
|
||||
{
|
||||
final T reference = stampedReference.getReference();
|
||||
stampedReference.compareAndSet(reference, reference, IN_USE, NOT_IN_USE);
|
||||
synchronizer.releaseShared(1);
|
||||
}
|
||||
}
|
||||
|
||||
private static class Synchronizer extends AbstractQueuedLongSynchronizer
|
||||
{
|
||||
private static final long serialVersionUID = 104753538004341218L;
|
||||
|
||||
private static ThreadLocal<Long> startTimeStamp = new ThreadLocal<Long>() {
|
||||
protected Long initialValue()
|
||||
{
|
||||
return System.nanoTime();
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
protected long tryAcquireShared(long arg)
|
||||
{
|
||||
Long waitStart = startTimeStamp.get();
|
||||
|
||||
// fairness
|
||||
if (hasQueuedPredecessors())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (getState() > waitStart)
|
||||
{
|
||||
startTimeStamp.remove();
|
||||
return 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
protected boolean tryReleaseShared(long arg)
|
||||
{
|
||||
setState(System.nanoTime());
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,117 +0,0 @@
|
||||
package com.zaxxer.hikari.util;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.LinkedList;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
public class ConcurrentBag<T>
|
||||
{
|
||||
private static sun.misc.Unsafe unsafe = getUnsafe();
|
||||
|
||||
private LinkedList<LinkedList<T>> sharedList;
|
||||
|
||||
private ThreadLocal<LinkedList<T>> threadList = new ThreadLocal<LinkedList<T>>() {
|
||||
protected java.util.LinkedList<T> initialValue()
|
||||
{
|
||||
LinkedList<T> list = new LinkedList<T>();
|
||||
sharedList.add(list);
|
||||
return list;
|
||||
}
|
||||
};
|
||||
|
||||
public ConcurrentBag()
|
||||
{
|
||||
sharedList = new LinkedList<>();
|
||||
}
|
||||
|
||||
@SuppressWarnings("restriction")
|
||||
private static sun.misc.Unsafe getUnsafe()
|
||||
{
|
||||
try
|
||||
{
|
||||
Field f = sun.misc.Unsafe.class.getDeclaredField("theUnsafe");
|
||||
f.setAccessible(true);
|
||||
return (sun.misc.Unsafe) f.get(null);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RuntimeException("Cannot access sun.misc.Unsafe");
|
||||
}
|
||||
}
|
||||
|
||||
private static class SinglyLinkedList<T>
|
||||
{
|
||||
private ReentrantLock putLock = new ReentrantLock();
|
||||
private ReentrantLock takeLock = new ReentrantLock();
|
||||
|
||||
Node<T> head;
|
||||
Node<T> tail;
|
||||
|
||||
void add(T value)
|
||||
{
|
||||
Node<T> node = new Node<T>(value);
|
||||
final ReentrantLock putLock = this.putLock;
|
||||
putLock.lock();
|
||||
try
|
||||
{
|
||||
if (head == null)
|
||||
{
|
||||
head = tail = node;
|
||||
}
|
||||
else
|
||||
{
|
||||
tail.next = node;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
putLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void remove(T value)
|
||||
{
|
||||
final ReentrantLock putLock = this.putLock;
|
||||
final ReentrantLock takeLock = this.takeLock;
|
||||
putLock.lock();
|
||||
takeLock.lock();
|
||||
try
|
||||
{
|
||||
Node<T> node = head;
|
||||
Node<T> prev = null;
|
||||
while (node != null)
|
||||
{
|
||||
if (node.value == value)
|
||||
{
|
||||
if (prev == null)
|
||||
{
|
||||
head = node;
|
||||
}
|
||||
else
|
||||
{
|
||||
prev.next = node.next;
|
||||
}
|
||||
break;
|
||||
}
|
||||
node = node.next;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
takeLock.unlock();
|
||||
putLock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class Node<E>
|
||||
{
|
||||
E value;
|
||||
Node<E> next;
|
||||
|
||||
Node(E value)
|
||||
{
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue