shz.core.queue.p.ConcurrentPQueue Maven / Gradle / Ivy
package shz.core.queue.p;
import shz.core.NullHelp;
import shz.core.lock.ReadWriteLockHolder;
import java.io.*;
import java.util.Arrays;
import java.util.Comparator;
@SuppressWarnings("unchecked")
public final class ConcurrentPQueue extends ReadWriteLockHolder implements Serializable {
private static final long serialVersionUID = -4626363787236007870L;
final int capacity;
transient E[] queue;
transient int size;
final Comparator super E> comparator;
public ConcurrentPQueue(int capacity, Comparator super E> comparator) {
NullHelp.requireNon(capacity < 1);
NullHelp.requireNonNull(comparator);
this.capacity = capacity;
this.comparator = comparator;
queue = (E[]) new Object[capacity];
}
public ConcurrentPQueue(Comparator super E> comparator) {
this(16, comparator);
}
public static ConcurrentPQueue of(int capacity, Comparator super E> comparator) {
return new ConcurrentPQueue<>(capacity, comparator);
}
public static ConcurrentPQueue of(Comparator super E> comparator) {
return new ConcurrentPQueue<>(comparator);
}
public int size() {
readLock.lock();
try {
return size;
} finally {
readLock.unlock();
}
}
public boolean isEmpty() {
readLock.lock();
try {
return size == 0;
} finally {
readLock.unlock();
}
}
public void offer(E e) {
writeLock.lock();
try {
int i = size;
if (i >= queue.length) grow(i + 1);
size = i + 1;
if (i == 0) queue[0] = e;
else siftUp(i, e);
} finally {
writeLock.unlock();
}
}
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private void grow(int minCapacity) {
int oldCapacity = queue.length;
int newCapacity = oldCapacity + (oldCapacity < 64 ? oldCapacity + 2 : oldCapacity >> 1);
if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity);
queue = Arrays.copyOf(queue, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) throw new OutOfMemoryError();
return minCapacity > MAX_ARRAY_SIZE ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
}
private void siftUp(int k, E x) {
while (k > 0) {
int parent = (k - 1) >>> 1;
E e = queue[parent];
if (comparator.compare(x, e) > 0) break;
queue[k] = e;
k = parent;
}
queue[k] = x;
}
public E poll() {
writeLock.lock();
try {
if (size == 0) return null;
int s = --size;
E result = queue[0];
E x = queue[s];
queue[s] = null;
if (s != 0) siftDown(0, x);
return result;
} finally {
writeLock.unlock();
}
}
private void siftDown(int k, E x) {
int half = size >>> 1;
while (k < half) {
int child = (k << 1) + 1;
E c = queue[child];
int right = child + 1;
if (right < size && comparator.compare(c, queue[right]) > 0) c = queue[child = right];
if (comparator.compare(x, c) < 0) break;
queue[k] = c;
k = child;
}
queue[k] = x;
}
public E peek() {
readLock.lock();
try {
return size == 0 ? null : queue[0];
} finally {
readLock.unlock();
}
}
private void writeObject(ObjectOutputStream oos) throws IOException {
oos.defaultWriteObject();
}
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ois.defaultReadObject();
queue = (E[]) new Object[capacity];
}
}