package net.minestom.server.thread; import net.minestom.server.MinecraftServer; import net.minestom.server.lock.Acquisition; import net.minestom.server.utils.validate.Check; import org.jetbrains.annotations.NotNull; import java.util.ArrayDeque; import java.util.Queue; import java.util.concurrent.CountDownLatch; public class BatchThread extends Thread { private final BatchRunnable runnable; private final BatchQueue queue; public BatchThread(@NotNull BatchRunnable runnable, int number) { super(runnable, MinecraftServer.THREAD_NAME_TICK + "-" + number); this.runnable = runnable; this.queue = new BatchQueue(); this.runnable.setLinkedThread(this); } @NotNull public BatchRunnable getMainRunnable() { return runnable; } @NotNull public BatchQueue getQueue() { return queue; } public void shutdown() { this.runnable.stop = true; } public static class BatchRunnable implements Runnable { private volatile boolean stop; private BatchThread batchThread; private volatile boolean inTick; private volatile CountDownLatch countDownLatch; private final Queue<Runnable> queue = new ArrayDeque<>(); private final Object tickLock = new Object(); @Override public void run() { Check.notNull(batchThread, "The linked BatchThread cannot be null!"); while (!stop) { // The latch is necessary to control the tick rates if (countDownLatch == null) continue; synchronized (tickLock) { this.inTick = true; // Execute all pending runnable Runnable runnable; while ((runnable = queue.poll()) != null) { runnable.run(); } // Execute waiting acquisition { Acquisition.processThreadTick(batchThread.getQueue()); } this.countDownLatch.countDown(); this.countDownLatch = null; this.inTick = false; // Wait for the next notify (game tick) try { this.tickLock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } public synchronized void startTick(@NotNull CountDownLatch countDownLatch, Runnable runnable) { synchronized (tickLock) { this.queue.add(runnable); this.countDownLatch = countDownLatch; this.tickLock.notifyAll(); } } public boolean isInTick() { return inTick; } private void setLinkedThread(BatchThread batchThread) { this.batchThread = batchThread; } } }