diff --git a/src/main/java/net/minestom/server/acquirable/Acquirable.java b/src/main/java/net/minestom/server/acquirable/Acquirable.java index d3a3b6139..50dad20bf 100644 --- a/src/main/java/net/minestom/server/acquirable/Acquirable.java +++ b/src/main/java/net/minestom/server/acquirable/Acquirable.java @@ -84,12 +84,11 @@ public interface Acquirable { default @NotNull Acquired lock() { var optional = local(); if (optional.isPresent()) { - return new Acquired<>(optional.get(), false, null); + return Acquired.local(optional.get()); } else { final Thread currentThread = Thread.currentThread(); final TickThread tickThread = getHandler().getTickThread(); - var lock = Acquired.acquireEnter(currentThread, tickThread); - return new Acquired<>(unwrap(), true, lock); + return Acquired.locked(unwrap(), currentThread, tickThread); } } diff --git a/src/main/java/net/minestom/server/acquirable/AcquirableCollection.java b/src/main/java/net/minestom/server/acquirable/AcquirableCollection.java index 2329bac2d..accad5234 100644 --- a/src/main/java/net/minestom/server/acquirable/AcquirableCollection.java +++ b/src/main/java/net/minestom/server/acquirable/AcquirableCollection.java @@ -26,11 +26,11 @@ public class AcquirableCollection implements Collection> { final TickThread tickThread = entry.getKey(); final List values = entry.getValue(); - var lock = Acquired.acquireEnter(currentThread, tickThread); + var lock = AcquirableImpl.enter(currentThread, tickThread); for (E value : values) { consumer.accept(value); } - Acquired.acquireLeave(lock); + AcquirableImpl.leave(lock); } } } diff --git a/src/main/java/net/minestom/server/acquirable/AcquirableImpl.java b/src/main/java/net/minestom/server/acquirable/AcquirableImpl.java index bcda8ebc8..809c15253 100644 --- a/src/main/java/net/minestom/server/acquirable/AcquirableImpl.java +++ b/src/main/java/net/minestom/server/acquirable/AcquirableImpl.java @@ -1,9 +1,12 @@ package net.minestom.server.acquirable; import net.minestom.server.entity.Entity; +import net.minestom.server.thread.TickThread; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.locks.ReentrantLock; import java.util.stream.Stream; class AcquirableImpl implements Acquirable { @@ -11,6 +14,11 @@ class AcquirableImpl implements Acquirable { protected static final ThreadLocal> CURRENT_ENTITIES = ThreadLocal.withInitial(Stream::empty); protected static final AtomicLong WAIT_COUNTER_NANO = new AtomicLong(); + /** + * Global lock used for synchronization. + */ + private static final ReentrantLock GLOBAL_LOCK = new ReentrantLock(); + private final T value; private final Acquirable.Handler handler; @@ -28,4 +36,42 @@ class AcquirableImpl implements Acquirable { public @NotNull Acquirable.Handler getHandler() { return handler; } + + protected static @Nullable ReentrantLock enter(@Nullable Thread currentThread, @Nullable TickThread elementThread) { + // Monitoring + long time = System.nanoTime(); + + ReentrantLock currentLock; + { + final TickThread current = currentThread instanceof TickThread ? + (TickThread) currentThread : null; + currentLock = current != null && current.getLock().isHeldByCurrentThread() ? + current.getLock() : null; + } + if (currentLock != null) + currentLock.unlock(); + + GLOBAL_LOCK.lock(); + + if (currentLock != null) + currentLock.lock(); + + final var lock = elementThread != null ? elementThread.getLock() : null; + final boolean acquired = lock == null || lock.isHeldByCurrentThread(); + if (!acquired) { + lock.lock(); + } + + // Monitoring + AcquirableImpl.WAIT_COUNTER_NANO.addAndGet(System.nanoTime() - time); + + return !acquired ? lock : null; + } + + protected static void leave(@Nullable ReentrantLock lock) { + if (lock != null) { + lock.unlock(); + } + GLOBAL_LOCK.unlock(); + } } diff --git a/src/main/java/net/minestom/server/acquirable/Acquired.java b/src/main/java/net/minestom/server/acquirable/Acquired.java index 8cf5ed3a1..0a46ed54c 100644 --- a/src/main/java/net/minestom/server/acquirable/Acquired.java +++ b/src/main/java/net/minestom/server/acquirable/Acquired.java @@ -3,17 +3,11 @@ package net.minestom.server.acquirable; import net.minestom.server.thread.TickThread; import net.minestom.server.utils.validate.Check; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.concurrent.locks.ReentrantLock; public class Acquired { - /** - * Global lock used for synchronization. - */ - private static final ReentrantLock GLOBAL_LOCK = new ReentrantLock(); - private final T value; private final boolean locked; @@ -21,11 +15,19 @@ public class Acquired { private boolean unlocked; - protected Acquired(@NotNull T value, - boolean locked, @Nullable ReentrantLock lock) { + protected static Acquired local(@NotNull T value) { + return new Acquired<>(value, false, null, null); + } + + protected static Acquired locked(@NotNull T value, Thread currentThread, TickThread tickThread) { + return new Acquired<>(value, true, currentThread, tickThread); + } + + private Acquired(@NotNull T value, + boolean locked, Thread currentThread, TickThread tickThread) { this.value = value; this.locked = locked; - this.lock = lock; + this.lock = locked ? AcquirableImpl.enter(currentThread, tickThread) : null; } public @NotNull T get() { @@ -38,45 +40,7 @@ public class Acquired { this.unlocked = true; if (!locked) return; - acquireLeave(lock); - } - - protected static @Nullable ReentrantLock acquireEnter(@Nullable Thread currentThread, @Nullable TickThread elementThread) { - // Monitoring - long time = System.nanoTime(); - - ReentrantLock currentLock; - { - final TickThread current = currentThread instanceof TickThread ? - (TickThread) currentThread : null; - currentLock = current != null && current.getLock().isHeldByCurrentThread() ? - current.getLock() : null; - } - if (currentLock != null) - currentLock.unlock(); - - GLOBAL_LOCK.lock(); - - if (currentLock != null) - currentLock.lock(); - - final var lock = elementThread != null ? elementThread.getLock() : null; - final boolean acquired = lock == null || lock.isHeldByCurrentThread(); - if (!acquired) { - lock.lock(); - } - - // Monitoring - AcquirableImpl.WAIT_COUNTER_NANO.addAndGet(System.nanoTime() - time); - - return !acquired ? lock : null; - } - - protected static void acquireLeave(@Nullable ReentrantLock lock) { - if (lock != null) { - lock.unlock(); - } - GLOBAL_LOCK.unlock(); + AcquirableImpl.leave(lock); } private void checkLock() {