org.redisson.misc.FastRemovalQueue Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of redisson-all Show documentation
Show all versions of redisson-all Show documentation
Easy Redis Java client and Real-Time Data Platform. Valkey compatible. Sync/Async/RxJava3/Reactive API. Client side caching. Over 50 Redis based Java objects and services: JCache API, Apache Tomcat, Hibernate, Spring, Set, Multimap, SortedSet, Map, List, Queue, Deque, Semaphore, Lock, AtomicLong, Map Reduce, Bloom filter, Scheduler, RPC
/**
* Copyright (c) 2013-2024 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.misc;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Thread-safe queue with O(1) complexity for removal operation.
*
* @author Nikita Koksharov
*
* @param element type
*/
public final class FastRemovalQueue {
private final Map> index = new ConcurrentHashMap<>();
private final DoublyLinkedList list = new DoublyLinkedList<>();
public void add(E element) {
Node newNode = new Node<>(element);
if (index.putIfAbsent(element, newNode) == null) {
list.add(newNode);
}
}
public boolean moveToTail(E element) {
Node node = index.get(element);
if (node != null) {
list.moveToTail(node);
return true;
}
return false;
}
public boolean remove(E element) {
Node node = index.remove(element);
if (node != null) {
return list.remove(node);
}
return false;
}
public int size() {
return index.size();
}
public E poll() {
Node node = list.removeFirst();
if (node != null) {
index.remove(node.value);
return node.value;
}
return null;
}
public void clear() {
index.clear();
list.clear();
}
static class Node {
private final E value;
private Node prev;
private Node next;
private boolean deleted;
Node(E value) {
this.value = value;
}
public void setDeleted() {
deleted = true;
}
public boolean isDeleted() {
return deleted;
}
}
static class DoublyLinkedList {
private final WrappedLock lock = new WrappedLock();
private Node head;
private Node tail;
DoublyLinkedList() {
}
public void clear() {
lock.execute(() -> {
head = null;
tail = null;
});
}
public void add(Node newNode) {
lock.execute(() -> {
addNode(newNode);
});
}
private void addNode(Node newNode) {
Node currentTail = tail;
tail = newNode;
if (currentTail == null) {
head = newNode;
} else {
newNode.prev = currentTail;
currentTail.next = newNode;
}
}
public boolean remove(Node node) {
Boolean r = lock.execute(() -> {
if (node.isDeleted()) {
return false;
}
removeNode(node);
node.setDeleted();
return true;
});
return Boolean.TRUE.equals(r);
}
private void removeNode(Node node) {
Node prevNode = node.prev;
Node nextNode = node.next;
if (prevNode != null) {
prevNode.next = nextNode;
} else {
head = nextNode;
}
if (nextNode != null) {
nextNode.prev = prevNode;
} else {
tail = prevNode;
}
}
public void moveToTail(Node node) {
lock.execute(() -> {
if (node.isDeleted()) {
return;
}
removeNode(node);
node.prev = null;
node.next = null;
addNode(node);
});
}
public Node removeFirst() {
return lock.execute(() -> {
Node currentHead = head;
if (head == tail) {
head = null;
tail = null;
} else {
head = head.next;
head.prev = null;
}
if (currentHead != null) {
currentHead.setDeleted();
}
return currentHead;
});
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy