Use of a ScheduledExecutorService for the server ticks (instead of Thread#sleep)

This commit is contained in:
Felix Cravic 2020-11-28 21:50:34 +01:00
parent a7b6a20cae
commit 1f2e4de0b3
4 changed files with 32 additions and 53 deletions

View File

@ -73,8 +73,6 @@ public final class MinecraftServer {
// Threads // Threads
public static final String THREAD_NAME_BENCHMARK = "Ms-Benchmark"; public static final String THREAD_NAME_BENCHMARK = "Ms-Benchmark";
public static final String THREAD_NAME_MAIN_UPDATE = "Ms-MainUpdate";
public static final String THREAD_NAME_TICK = "Ms-Tick"; public static final String THREAD_NAME_TICK = "Ms-Tick";
public static final String THREAD_NAME_BLOCK_BATCH = "Ms-BlockBatchPool"; public static final String THREAD_NAME_BLOCK_BATCH = "Ms-BlockBatchPool";

View File

@ -5,14 +5,11 @@ import net.minestom.server.instance.Instance;
import net.minestom.server.instance.InstanceManager; import net.minestom.server.instance.InstanceManager;
import net.minestom.server.thread.PerInstanceThreadProvider; import net.minestom.server.thread.PerInstanceThreadProvider;
import net.minestom.server.thread.ThreadProvider; import net.minestom.server.thread.ThreadProvider;
import net.minestom.server.utils.thread.MinestomThread;
import net.minestom.server.utils.validate.Check; import net.minestom.server.utils.validate.Check;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.List; import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.function.LongConsumer; import java.util.function.LongConsumer;
/** /**
@ -23,7 +20,8 @@ import java.util.function.LongConsumer;
*/ */
public final class UpdateManager { public final class UpdateManager {
private final ExecutorService mainUpdate = new MinestomThread(1, MinecraftServer.THREAD_NAME_MAIN_UPDATE); private final ScheduledExecutorService updateExecutionService = Executors.newSingleThreadScheduledExecutor();
private boolean stopRequested; private boolean stopRequested;
private ThreadProvider threadProvider; private ThreadProvider threadProvider;
@ -47,45 +45,36 @@ public final class UpdateManager {
* Starts the server loop in the update thread. * Starts the server loop in the update thread.
*/ */
protected void start() { protected void start() {
mainUpdate.execute(() -> { final EntityManager entityManager = MinecraftServer.getEntityManager();
final EntityManager entityManager = MinecraftServer.getEntityManager();
final long tickDistance = MinecraftServer.TICK_MS * 1000000; updateExecutionService.scheduleAtFixedRate(() -> {
long currentTime; if (stopRequested) {
while (!stopRequested) { updateExecutionService.shutdown();
currentTime = System.nanoTime(); return;
final long tickStart = System.currentTimeMillis();
// Tick start callbacks
doTickCallback(tickStartCallbacks, tickStart);
// Waiting players update (newly connected clients waiting to get into the server)
entityManager.updateWaitingPlayers();
// Keep Alive Handling
entityManager.handleKeepAlive(tickStart);
// Server tick (chunks/entities)
serverTick(tickStart);
// the time that the tick took in nanoseconds
final long tickTime = System.nanoTime() - currentTime;
// Tick end callbacks
doTickCallback(tickEndCallbacks, tickTime / 1000000L);
// Sleep until next tick
final long sleepTime = Math.max(1, (tickDistance - tickTime) / 1000000L);
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
if (!stopRequested)
e.printStackTrace();
}
} }
}); long currentTime = System.nanoTime();
final long tickStart = System.currentTimeMillis();
// Tick start callbacks
doTickCallback(tickStartCallbacks, tickStart);
// Waiting players update (newly connected clients waiting to get into the server)
entityManager.updateWaitingPlayers();
// Keep Alive Handling
entityManager.handleKeepAlive(tickStart);
// Server tick (chunks/entities)
serverTick(tickStart);
// the time that the tick took in nanoseconds
final long tickTime = System.nanoTime() - currentTime;
// Tick end callbacks
doTickCallback(tickEndCallbacks, tickTime / 1000000L);
}, 0, MinecraftServer.TICK_MS, TimeUnit.MILLISECONDS);
} }
/** /**

View File

@ -37,7 +37,6 @@ public final class BenchmarkManager {
THREAD_MX_BEAN.setThreadContentionMonitoringEnabled(true); THREAD_MX_BEAN.setThreadContentionMonitoringEnabled(true);
THREAD_MX_BEAN.setThreadCpuTimeEnabled(true); THREAD_MX_BEAN.setThreadCpuTimeEnabled(true);
THREADS.add(THREAD_NAME_MAIN_UPDATE);
THREADS.add(THREAD_NAME_BLOCK_BATCH); THREADS.add(THREAD_NAME_BLOCK_BATCH);
THREADS.add(THREAD_NAME_SCHEDULER); THREADS.add(THREAD_NAME_SCHEDULER);
THREADS.add(THREAD_NAME_TICK); THREADS.add(THREAD_NAME_TICK);

View File

@ -217,18 +217,11 @@ public final class NettyServer {
* Stops the server and the various services. * Stops the server and the various services.
*/ */
public void stop() { public void stop() {
// FIXME: fix "java.util.concurrent.RejectedExecutionException: event executor terminated"
// TODO: probably because we are doing IO after #stop() is executed
try { try {
this.serverChannel.close().sync(); this.serverChannel.close().sync();
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
this.worker.shutdownGracefully().await(); this.worker.shutdownGracefully().await();
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
this.boss.shutdownGracefully().await(); this.boss.shutdownGracefully().await();
} catch (InterruptedException e) { } catch (InterruptedException e) {
e.printStackTrace(); e.printStackTrace();