Executor
This page explains how to use executors provided by the core system.
What are executors used for?
You can access these executors via the BukkitExecutor.
There are three main types:
- sync
- async
- external async (ExecutorService-based)
Each method has its own purpose.
Always use this class instead of Bukkit.getScheduler() to keep scheduling consistent across the project.
Quick Examples
Sync delayed task (5 ticks later)
CorePlugin plugin = getPlugin();
BukkitExecutor.runSyncDelayed(plugin, () -> {
if (player.isOnline() && !player.isSwitchingServer()) {
player.sendMessage("Time is running!");
}
}, 5L);
Switching between sync -> async -> sync
CorePlugin plugin = getPlugin();
BukkitExecutor.runAsync(plugin, () -> {
HeavyData heavyData = loadHeavyDataFromSql();
BukkitExecutor.runSync(plugin, () -> {
if (player.isOnline() && !player.isSwitchingServer()) {
player.sendMessage("Finished loading " + heavyData.toString());
}
});
});
Running something after a specific time (independent of ticks)
Uses an external executor - make sure to handle errors properly.
BukkitExecutor.executorAsyncDelayed(() -> {
BukkitExecutor.runSync(plugin, () -> {
try {
if (player.isOnline() && !player.isSwitchingServer()) {
player.sendMessage("20 seconds passed by!");
}
} catch (Throwable throwable) {
plugin.getLogger().log(Level.WARNING, "Failed to send message!", throwable);
}
});
}, 20L, TimeUnit.SECONDS);
When to use
- When you want to delay an action
- When you need to run thread-blocking operations (use async)
- When you want to execute something after a fixed time (e.g. seconds), independent of the server tick rate
Best Practices
- Don't create unnecessary tasks.
- Only use tasks when needed - avoid spreading logic across multiple tasks without reason.
- Always switch back to sync before interacting with non-thread-safe APIs (e.g. Bukkit/player logic).
Common Pitfalls
- Running async tasks and forgetting to switch back to sync before interacting with players or Bukkit APIs.
- Not re-validating conditions after returning from async to sync. Example: A player has 5 coins → async task runs → meanwhile the player spends the coins → you return to sync and still assume they have 5 coins. Always validate state again before executing critical logic.