mirror of
https://github.com/BX-Team/DivineMC.git
synced 2025-12-22 08:19:19 +00:00
Async Join Thread and executors shutdown
This commit is contained in:
@@ -0,0 +1,78 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||||
|
Date: Wed, 11 Jun 2025 20:15:37 +0300
|
||||||
|
Subject: [PATCH] Async Join Thread
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||||
|
index 9285697a1da3f216e03b8ea824f07f7f7c716c53..de4d2bd780c98c8c06db5e9375d447dae4d4429e 100644
|
||||||
|
--- a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||||
|
+++ b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||||
|
@@ -186,22 +186,25 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Paper end - Add Velocity IP Forwarding Support
|
||||||
|
- // CraftBukkit start
|
||||||
|
- // Paper start - Cache authenticator threads
|
||||||
|
- authenticatorPool.execute(() -> {
|
||||||
|
+ // DivineMC start - Async Join Thread
|
||||||
|
+ org.bxteam.divinemc.server.network.AsyncJoinHandler.runAsync(() -> {
|
||||||
|
try {
|
||||||
|
GameProfile gameprofile = ServerLoginPacketListenerImpl.this.createOfflineProfile(ServerLoginPacketListenerImpl.this.requestedUsername); // Spigot
|
||||||
|
|
||||||
|
gameprofile = ServerLoginPacketListenerImpl.this.callPlayerPreLoginEvents(gameprofile); // Paper - Add more fields to AsyncPlayerPreLoginEvent
|
||||||
|
ServerLoginPacketListenerImpl.LOGGER.info("UUID of player {} is {}", gameprofile.getName(), gameprofile.getId());
|
||||||
|
- ServerLoginPacketListenerImpl.this.startClientVerification(gameprofile);
|
||||||
|
+ return gameprofile;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
ServerLoginPacketListenerImpl.this.disconnect("Failed to verify username!");
|
||||||
|
ServerLoginPacketListenerImpl.this.server.server.getLogger().log(java.util.logging.Level.WARNING, "Exception verifying " + ServerLoginPacketListenerImpl.this.requestedUsername, ex);
|
||||||
|
+ return null;
|
||||||
|
+ }
|
||||||
|
+ }, (gameprofile) -> {
|
||||||
|
+ if (gameprofile != null) {
|
||||||
|
+ ServerLoginPacketListenerImpl.this.startClientVerification(gameprofile);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
- // Paper end - Cache authenticator threads
|
||||||
|
- // CraftBukkit end
|
||||||
|
+ // DivineMC end - Async Join Thread
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -259,7 +262,8 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Paper start - Cache authenticator threads
|
||||||
|
- authenticatorPool.execute(new Runnable() {
|
||||||
|
+ // DivineMC start - Async Join Thread
|
||||||
|
+ org.bxteam.divinemc.server.network.AsyncJoinHandler.runAsync(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
String string1 = Objects.requireNonNull(ServerLoginPacketListenerImpl.this.requestedUsername, "Player name not initialized");
|
||||||
|
@@ -410,16 +414,23 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
|
||||||
|
//TODO Update handling for lazy sessions, might not even have to do anything?
|
||||||
|
|
||||||
|
// Proceed with login
|
||||||
|
- authenticatorPool.execute(() -> {
|
||||||
|
+ // DivineMC start - Async Join Thread
|
||||||
|
+ org.bxteam.divinemc.server.network.AsyncJoinHandler.runAsync(() -> {
|
||||||
|
try {
|
||||||
|
final GameProfile gameprofile = this.callPlayerPreLoginEvents(this.authenticatedProfile);
|
||||||
|
ServerLoginPacketListenerImpl.LOGGER.info("UUID of player {} is {}", gameprofile.getName(), gameprofile.getId());
|
||||||
|
- ServerLoginPacketListenerImpl.this.startClientVerification(gameprofile);
|
||||||
|
+ return gameprofile;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
disconnect("Failed to verify username!");
|
||||||
|
server.server.getLogger().log(java.util.logging.Level.WARNING, "Exception verifying " + this.authenticatedProfile.getName(), ex);
|
||||||
|
+ return null;
|
||||||
|
+ }
|
||||||
|
+ }, (gameprofile) -> {
|
||||||
|
+ if (gameprofile != null) {
|
||||||
|
+ ServerLoginPacketListenerImpl.this.startClientVerification(gameprofile);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
+ // DivineMC end - Async Join Thread
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Paper end - Add Velocity IP Forwarding Support
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||||
|
Date: Thu, 10 Jul 2025 17:39:29 +0300
|
||||||
|
Subject: [PATCH] Shutdown executors
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||||
|
index 6361d8abdeb045923e8ce64f02cbb7a9ed949d1e..b31a4edee0616a63026f7a4335205f2d99d2f641 100644
|
||||||
|
--- a/net/minecraft/server/MinecraftServer.java
|
||||||
|
+++ b/net/minecraft/server/MinecraftServer.java
|
||||||
|
@@ -1081,6 +1081,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||||
|
// Paper end - rewrite chunk system
|
||||||
|
// Paper start - Improved watchdog support - move final shutdown items here
|
||||||
|
Util.shutdownExecutors();
|
||||||
|
+ org.bxteam.divinemc.util.ExecutorShutdown.shutdown(this); // DivineMC - Shutdown executors
|
||||||
|
try {
|
||||||
|
net.minecrell.terminalconsole.TerminalConsoleAppender.close(); // Paper - Use TerminalConsoleAppender
|
||||||
|
} catch (final Exception ignored) {
|
||||||
@@ -11,6 +11,7 @@ import org.bukkit.configuration.ConfigurationSection;
|
|||||||
import org.bukkit.configuration.MemoryConfiguration;
|
import org.bukkit.configuration.MemoryConfiguration;
|
||||||
import org.bxteam.divinemc.config.annotations.Experimental;
|
import org.bxteam.divinemc.config.annotations.Experimental;
|
||||||
import org.bxteam.divinemc.entity.pathfinding.PathfindTaskRejectPolicy;
|
import org.bxteam.divinemc.entity.pathfinding.PathfindTaskRejectPolicy;
|
||||||
|
import org.bxteam.divinemc.server.network.AsyncJoinHandler;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.simpleyaml.configuration.comments.CommentType;
|
import org.simpleyaml.configuration.comments.CommentType;
|
||||||
import org.simpleyaml.configuration.file.YamlFile;
|
import org.simpleyaml.configuration.file.YamlFile;
|
||||||
@@ -229,6 +230,11 @@ public class DivineConfig {
|
|||||||
public static int asyncEntityTrackerKeepalive = 60;
|
public static int asyncEntityTrackerKeepalive = 60;
|
||||||
public static int asyncEntityTrackerQueueSize = 0;
|
public static int asyncEntityTrackerQueueSize = 0;
|
||||||
|
|
||||||
|
// Async Join Thread settings
|
||||||
|
public static boolean asyncJoinEnabled = true;
|
||||||
|
public static int asyncJoinThreadCount = 1;
|
||||||
|
public static boolean asyncJoinUseVirtualThreads = false;
|
||||||
|
|
||||||
// Async chunk sending settings
|
// Async chunk sending settings
|
||||||
public static boolean asyncChunkSendingEnabled = true;
|
public static boolean asyncChunkSendingEnabled = true;
|
||||||
|
|
||||||
@@ -240,6 +246,7 @@ public class DivineConfig {
|
|||||||
regionizedChunkTicking();
|
regionizedChunkTicking();
|
||||||
asyncPathfinding();
|
asyncPathfinding();
|
||||||
multithreadedTracker();
|
multithreadedTracker();
|
||||||
|
asyncJoinSettings();
|
||||||
asyncChunkSending();
|
asyncChunkSending();
|
||||||
asyncMobSpawning();
|
asyncMobSpawning();
|
||||||
}
|
}
|
||||||
@@ -333,6 +340,18 @@ public class DivineConfig {
|
|||||||
if (asyncEntityTrackerQueueSize <= 0) asyncEntityTrackerQueueSize = asyncEntityTrackerMaxThreads * 384;
|
if (asyncEntityTrackerQueueSize <= 0) asyncEntityTrackerQueueSize = asyncEntityTrackerMaxThreads * 384;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void asyncJoinSettings() {
|
||||||
|
asyncJoinEnabled = getBoolean(ConfigCategory.ASYNC.key("join-thread.enabled"), asyncJoinEnabled,
|
||||||
|
"Enables async join thread, which offloads player setup and connection tasks to a separate thread",
|
||||||
|
"This can significantly improve MSPT when multiple players are joining simultaneously");
|
||||||
|
asyncJoinThreadCount = getInt(ConfigCategory.ASYNC.key("join-thread.thread-count"), asyncJoinThreadCount,
|
||||||
|
"Number of threads to use for async join operations");
|
||||||
|
asyncJoinUseVirtualThreads = getBoolean(ConfigCategory.ASYNC.key("join-thread.use-virtual-threads"), asyncJoinUseVirtualThreads,
|
||||||
|
"Whether to use virtual threads for async join operations (requires Java 21+)");
|
||||||
|
|
||||||
|
AsyncJoinHandler.init(asyncJoinEnabled, asyncJoinThreadCount);
|
||||||
|
}
|
||||||
|
|
||||||
private static void asyncChunkSending() {
|
private static void asyncChunkSending() {
|
||||||
asyncChunkSendingEnabled = getBoolean(ConfigCategory.ASYNC.key("chunk-sending.enable"), asyncChunkSendingEnabled,
|
asyncChunkSendingEnabled = getBoolean(ConfigCategory.ASYNC.key("chunk-sending.enable"), asyncChunkSendingEnabled,
|
||||||
"Makes chunk sending asynchronous, which can significantly reduce main thread load when many players are loading chunks.");
|
"Makes chunk sending asynchronous, which can significantly reduce main thread load when many players are loading chunks.");
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ public class AsyncPathProcessor {
|
|||||||
private static final Logger LOGGER = LogManager.getLogger(THREAD_PREFIX);
|
private static final Logger LOGGER = LogManager.getLogger(THREAD_PREFIX);
|
||||||
|
|
||||||
private static long lastWarnMillis = System.currentTimeMillis();
|
private static long lastWarnMillis = System.currentTimeMillis();
|
||||||
private static final ThreadPoolExecutor pathProcessingExecutor = new ThreadPoolExecutor(
|
public static final ThreadPoolExecutor PATH_PROCESSING_EXECUTOR = new ThreadPoolExecutor(
|
||||||
1,
|
1,
|
||||||
DivineConfig.AsyncCategory.asyncPathfindingMaxThreads,
|
DivineConfig.AsyncCategory.asyncPathfindingMaxThreads,
|
||||||
DivineConfig.AsyncCategory.asyncPathfindingKeepalive, TimeUnit.SECONDS,
|
DivineConfig.AsyncCategory.asyncPathfindingKeepalive, TimeUnit.SECONDS,
|
||||||
@@ -63,7 +63,7 @@ public class AsyncPathProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected static CompletableFuture<Void> queue(@NotNull AsyncPath path) {
|
protected static CompletableFuture<Void> queue(@NotNull AsyncPath path) {
|
||||||
return CompletableFuture.runAsync(path::process, pathProcessingExecutor)
|
return CompletableFuture.runAsync(path::process, PATH_PROCESSING_EXECUTOR)
|
||||||
.orTimeout(60L, TimeUnit.SECONDS)
|
.orTimeout(60L, TimeUnit.SECONDS)
|
||||||
.exceptionally(throwable -> {
|
.exceptionally(throwable -> {
|
||||||
if (throwable instanceof TimeoutException e) {
|
if (throwable instanceof TimeoutException e) {
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ public class MultithreadedTracker {
|
|||||||
private static final Logger LOGGER = LogManager.getLogger(THREAD_PREFIX);
|
private static final Logger LOGGER = LogManager.getLogger(THREAD_PREFIX);
|
||||||
|
|
||||||
private static long lastWarnMillis = System.currentTimeMillis();
|
private static long lastWarnMillis = System.currentTimeMillis();
|
||||||
private static final ThreadPoolExecutor TRACKER_EXECUTOR = new ThreadPoolExecutor(
|
public static final ThreadPoolExecutor TRACKER_EXECUTOR = new ThreadPoolExecutor(
|
||||||
getCorePoolSize(),
|
getCorePoolSize(),
|
||||||
getMaxPoolSize(),
|
getMaxPoolSize(),
|
||||||
getKeepAliveTime(), TimeUnit.SECONDS,
|
getKeepAliveTime(), TimeUnit.SECONDS,
|
||||||
|
|||||||
@@ -0,0 +1,102 @@
|
|||||||
|
package org.bxteam.divinemc.server.network;
|
||||||
|
|
||||||
|
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.bxteam.divinemc.config.DivineConfig;
|
||||||
|
import org.bxteam.divinemc.spark.ThreadDumperRegistry;
|
||||||
|
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
public class AsyncJoinHandler {
|
||||||
|
private static final String THREAD_PREFIX = "Async Join Thread";
|
||||||
|
public static final Logger LOGGER = LogManager.getLogger(AsyncJoinHandler.class.getSimpleName());
|
||||||
|
public static ExecutorService JOIN_EXECUTOR;
|
||||||
|
|
||||||
|
private static boolean enabled = false;
|
||||||
|
private static int threadCount = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the AsyncJoinHandler with configuration settings
|
||||||
|
*/
|
||||||
|
public static void init(boolean enabled, int threadCount) {
|
||||||
|
AsyncJoinHandler.enabled = enabled;
|
||||||
|
AsyncJoinHandler.threadCount = Math.max(1, threadCount);
|
||||||
|
|
||||||
|
if (enabled) {
|
||||||
|
if (JOIN_EXECUTOR != null) {
|
||||||
|
JOIN_EXECUTOR.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
JOIN_EXECUTOR = org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.virtualThreadsEnabled &&
|
||||||
|
DivineConfig.AsyncCategory.asyncJoinUseVirtualThreads
|
||||||
|
? Executors.newVirtualThreadPerTaskExecutor()
|
||||||
|
: Executors.newFixedThreadPool(
|
||||||
|
threadCount,
|
||||||
|
new ThreadFactoryBuilder()
|
||||||
|
.setNameFormat(THREAD_PREFIX)
|
||||||
|
.setDaemon(true)
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
|
||||||
|
ThreadDumperRegistry.REGISTRY.add(THREAD_PREFIX);
|
||||||
|
|
||||||
|
LOGGER.info("Initialized AsyncJoinHandler with {} threads", threadCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute a potentially blocking task asynchronously
|
||||||
|
*
|
||||||
|
* @param task The task to run asynchronously
|
||||||
|
* @param callback The callback to execute on the main thread when the task completes
|
||||||
|
* @param <T> The return type of the task
|
||||||
|
*/
|
||||||
|
public static <T> void runAsync(Supplier<T> task, java.util.function.Consumer<T> callback) {
|
||||||
|
if (!enabled || JOIN_EXECUTOR == null) {
|
||||||
|
T result = task.get();
|
||||||
|
callback.accept(result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CompletableFuture.supplyAsync(task, JOIN_EXECUTOR)
|
||||||
|
.thenAccept(result -> {
|
||||||
|
MinecraftServer.getServer().execute(() -> callback.accept(result));
|
||||||
|
})
|
||||||
|
.exceptionally(ex -> {
|
||||||
|
LOGGER.error("Error during async join operation", ex);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute a potentially blocking task asynchronously without a result
|
||||||
|
*
|
||||||
|
* @param asyncTask The task to run asynchronously
|
||||||
|
*/
|
||||||
|
public static void runAsync(Runnable asyncTask) {
|
||||||
|
if (!enabled || JOIN_EXECUTOR == null) {
|
||||||
|
asyncTask.run();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CompletableFuture.runAsync(asyncTask, JOIN_EXECUTOR)
|
||||||
|
.thenRun(() -> MinecraftServer.getServer().execute(asyncTask))
|
||||||
|
.exceptionally(ex -> {
|
||||||
|
LOGGER.error("Error during async join operation", ex);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the executor service for async join operations
|
||||||
|
*/
|
||||||
|
public static Executor getExecutor() {
|
||||||
|
return enabled && JOIN_EXECUTOR != null ? JOIN_EXECUTOR : Runnable::run;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,61 +1,62 @@
|
|||||||
package org.bxteam.divinemc.util;
|
package org.bxteam.divinemc.util;
|
||||||
|
|
||||||
import ca.spottedleaf.moonrise.common.util.TickThread;
|
import it.unimi.dsi.fastutil.PriorityQueue;
|
||||||
|
import it.unimi.dsi.fastutil.PriorityQueues;
|
||||||
|
import it.unimi.dsi.fastutil.objects.ObjectArrayFIFOQueue;
|
||||||
|
import net.minecraft.Util;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.bxteam.divinemc.spark.ThreadDumperRegistry;
|
import org.bxteam.divinemc.spark.ThreadDumperRegistry;
|
||||||
import java.util.concurrent.BlockingQueue;
|
import java.util.NoSuchElementException;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.locks.LockSupport;
|
||||||
|
|
||||||
public class AsyncProcessor {
|
public class AsyncProcessor implements Runnable {
|
||||||
private static final Logger LOGGER = LogManager.getLogger(AsyncProcessor.class);
|
private static final Logger LOGGER = LogManager.getLogger(AsyncProcessor.class);
|
||||||
|
|
||||||
private final BlockingQueue<Runnable> taskQueue;
|
public final Thread thread;
|
||||||
private final Thread workerThread;
|
private final PriorityQueue<Runnable> jobs = PriorityQueues.synchronize(new ObjectArrayFIFOQueue<>());
|
||||||
private volatile boolean isRunning;
|
private volatile boolean killswitch = false;
|
||||||
|
|
||||||
public AsyncProcessor(String threadName) {
|
public AsyncProcessor(String threadName) {
|
||||||
this.taskQueue = new LinkedBlockingQueue<>();
|
this.thread = Thread.ofPlatform()
|
||||||
this.isRunning = true;
|
.name(threadName)
|
||||||
|
.priority(Thread.NORM_PRIORITY - 1)
|
||||||
|
.daemon(false)
|
||||||
|
.uncaughtExceptionHandler(Util::onThreadException)
|
||||||
|
.unstarted(this);
|
||||||
|
}
|
||||||
|
|
||||||
this.workerThread = new TickThread(() -> {
|
public void start() {
|
||||||
while (isRunning || !taskQueue.isEmpty()) {
|
thread.start();
|
||||||
|
ThreadDumperRegistry.REGISTRY.add(thread.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void join(long millis) throws InterruptedException {
|
||||||
|
killswitch = true;
|
||||||
|
LockSupport.unpark(thread);
|
||||||
|
thread.join(millis);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void submit(Runnable runnable) {
|
||||||
|
jobs.enqueue(runnable);
|
||||||
|
LockSupport.unpark(thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
while (!killswitch) {
|
||||||
|
try {
|
||||||
|
Runnable runnable;
|
||||||
try {
|
try {
|
||||||
Runnable task = taskQueue.take();
|
runnable = jobs.dequeue();
|
||||||
task.run();
|
} catch (NoSuchElementException e) {
|
||||||
} catch (InterruptedException e) {
|
LockSupport.park();
|
||||||
Thread.currentThread().interrupt();
|
continue;
|
||||||
break;
|
|
||||||
} catch (Exception e) {
|
|
||||||
LOGGER.error("An unexpected error occurred when running async processor: {}", e.getMessage(), e);
|
|
||||||
}
|
}
|
||||||
|
runnable.run();
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOGGER.error("Failed to execute async job for thread {}", thread.getName(), e);
|
||||||
}
|
}
|
||||||
}, threadName);
|
|
||||||
|
|
||||||
ThreadDumperRegistry.REGISTRY.add(threadName);
|
|
||||||
this.workerThread.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void submit(Runnable task) {
|
|
||||||
if (!isRunning) {
|
|
||||||
throw new IllegalStateException("AsyncExecutor is not running.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
taskQueue.offer(task);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void shutdown() {
|
|
||||||
isRunning = false;
|
|
||||||
workerThread.interrupt();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void shutdownNow() {
|
|
||||||
isRunning = false;
|
|
||||||
workerThread.interrupt();
|
|
||||||
taskQueue.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isRunning() {
|
|
||||||
return isRunning;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package org.bxteam.divinemc.util;
|
||||||
|
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.bxteam.divinemc.entity.pathfinding.AsyncPathProcessor;
|
||||||
|
import org.bxteam.divinemc.entity.tracking.MultithreadedTracker;
|
||||||
|
import org.bxteam.divinemc.server.network.AsyncJoinHandler;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@SuppressWarnings("ConstantValue")
|
||||||
|
public class ExecutorShutdown {
|
||||||
|
public static final Logger LOGGER = LogManager.getLogger(ExecutorShutdown.class.getSimpleName());
|
||||||
|
|
||||||
|
public static void shutdown(MinecraftServer server) {
|
||||||
|
if (server.mobSpawnExecutor != null && server.mobSpawnExecutor.thread.isAlive()) {
|
||||||
|
LOGGER.info("Shutting down mob spawn executor...");
|
||||||
|
|
||||||
|
try {
|
||||||
|
server.mobSpawnExecutor.join(3000L);
|
||||||
|
} catch (InterruptedException ignored) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MultithreadedTracker.TRACKER_EXECUTOR != null) {
|
||||||
|
LOGGER.info("Shutting down mob tracker executor...");
|
||||||
|
MultithreadedTracker.TRACKER_EXECUTOR.shutdown();
|
||||||
|
|
||||||
|
try {
|
||||||
|
MultithreadedTracker.TRACKER_EXECUTOR.awaitTermination(10L, TimeUnit.SECONDS);
|
||||||
|
} catch (InterruptedException ignored) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AsyncPathProcessor.PATH_PROCESSING_EXECUTOR != null) {
|
||||||
|
LOGGER.info("Shutting down mob pathfinding processing executor...");
|
||||||
|
AsyncPathProcessor.PATH_PROCESSING_EXECUTOR.shutdown();
|
||||||
|
|
||||||
|
try {
|
||||||
|
AsyncPathProcessor.PATH_PROCESSING_EXECUTOR.awaitTermination(10L, TimeUnit.SECONDS);
|
||||||
|
} catch (InterruptedException ignored) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AsyncJoinHandler.JOIN_EXECUTOR != null) {
|
||||||
|
LOGGER.info("Shutting down async join executor...");
|
||||||
|
AsyncJoinHandler.JOIN_EXECUTOR.shutdown();
|
||||||
|
|
||||||
|
try {
|
||||||
|
AsyncJoinHandler.JOIN_EXECUTOR.awaitTermination(10L, TimeUnit.SECONDS);
|
||||||
|
} catch (InterruptedException ignored) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user