← Java tutorials

LESSON 35 / 40 · FREE TUTORIAL

Schedule Tasks

Hand over later execution to the scheduler

100–120 minutesEnvironment: JDK 21, ordinary Paper 1.21.11, client of the same version. Server plugins are loaded by Paper; only explicitly labeled rule tests use main.Paper plug-in practice

WHAT YOU WILL MAKE

60-second activity timer that can be started and stopped

The server needs to continue working and cannot sleep with the countdown. Use tick to schedule delayed and repeated tasks, save task handles, and ensure that repeated starts, manual cancellations, and server stops have clear results. Prerequisites: Lambda, command and object fields. The new project BlockAcademyL35 continues to use ordinary Paper1.21.11, Java21 and Lesson 31 build scripts.

Before you start: It is recommended to complete Lessons 30–34 first

01 / 12

Before starting: first recognize the running position

The first 30 lessons lay the foundation for ordinary Java programs. At this stage, the code is connected to the Paper server: the Minecraft client is responsible for entering the world, the server loads the plug-in, and the events and commands hand over player actions to your methods.

This book uses JDK 21 and Paper 1.21.11, and the client version is also consistent. The latest version on the download page may have changed, select it by version number. This book uses normal plugin.yml and the Bukkit API; no claims are made to support Folia at this stage.

The short examples in the picture frame are partial fragments. Read the location description of this section first, and do not save each as a plug-in. The file name will be clearly given for the complete file; when the same file is divided into multiple segments, they will be connected by number, and the package name, import and outer class will only appear once.

  • Prediction: Write success conditions and expected messages first.
  • Run: After successful construction, install and restart on the dedicated local test server.
  • Verification: Ordinary players, management identities and consoles take corresponding paths respectively.

02 / 12

The server uses tick to count beats

The timekeeper wanted to wait for one second, but he stood sleeping at the door of the server's main thread, and the players behind him lined up in a long queue. The scheduler can make an appointment for a later time, keeping the busy corridor open.

tick is the beat of server work. At normal 20 TPS, 20 ticks is about one second; when there is a lag, the actual time will be longer. Repeating tasks need to save the task handle, and they can be stopped when ending, canceling and deactivating.

The server uses tick to count beats
  1. tickServer working rhythm
  2. 20TPS20 ticks about 1 second
  3. Low TPSThe reality is that the wait will be longer

To clarify the unit and location, see the description in this section

long delayTicks = 5L * 20L;
long durationTicks = 60L * 20L;
Checklist
GoalNumber of ticks
3 seconds60
10 seconds200
60 seconds1200

03 / 12

Do it later. Don’t sleep where you are.

runTaskLater hands the task to the server and executes it after the specified tick. The current method can end first. Thread.sleep will block the current thread; placing it in the main thread of the server will allow other players to accompany you.

Do it later. Don’t sleep where you are.
  1. Register nowThe current method ends immediately
  2. Execute laterCheck players again after 60 ticks
  3. Still onlineSend message only if it is not null

Send a message to online players in three seconds · See the instructions in this section for the location

UUID id = player.getUniqueId();
getServer().getScheduler().runTaskLater(this, () -> {
    Player online = getServer().getPlayer(id);
    if (online != null) {
        online.sendMessage(Component.text("Three seconds prompt arrives!"));
    }
}, 60L);

Dangerous main thread wait · Intentional error, predict first and then fix

Thread.sleep(3000); // Don't wait like this in a command or sync event

04 / 12

Repeating tasks requires your own status

runTaskTimer receives first delay and repeat interval. The practice activity is broadcast immediately for 60 seconds, but you have to wait 20 ticks for the first subtraction; if you delay writing 0 and subtract immediately, the opening will be one second shorter.

Repeating tasks requires own status
  1. Initial value 10Display or save status first
  2. Wait 20 ticks for the first timeReduce to 9 again
  3. Return to zeroThe current callback cancels the task

Ten-second countdown experiment · See the instructions in this section for the location

new BukkitRunnable() {
    int seconds = 10;
    @Override
    public void run() {
        seconds--;
        getServer().broadcast(Component.text("Remaining " + seconds));
        if (seconds <= 0) cancel();
    }
}.runTaskTimer(this, 20L, 20L);

05 / 12

Only when you get the task ticket can you stop

The scheduler returns a BukkitTask, which is equivalent to a task ticket. The plug-in stores it in the field active. If active is null, it means idle; if start is received when there is a ticket, it tells the operator that the timer is already in progress.

Stop and think about it: If you execute the start command when the activity is already running, will there be an extra countdown? How to prove that the task is really canceled after it is stopped?

Only when you get the task ticket can you stop
  1. active is emptyOK to start
  2. active is not emptyRefuse to start the second time
  3. Uniform stopClear fields after cancel

Unified cancellation method · See the description in this section for the location

private void stopTimer() {
    if (active != null) active.cancel();
    active = null;
}

Prevent repeated startup · See the instructions in this section for the location

if (active != null) sender.sendMessage("Activity is already timing");
else startTimer();

06 / 12

World operations remain on the server main thread

This lesson all uses synchronous scheduling, and broadcast and world operations are executed on the main thread of the server. Asynchronous tasks are suitable for certain time-consuming calculations or I/O, but many Bukkit world APIs are not accessible from asynchronous threads; asynchrony also introduces contention for shared data.

World operations remain on the server main thread
  1. Synchronous short callbackManipulating Players and the World
  2. Time consuming I/OUnable to block callbacks per second
  3. Ordinary PaperThis chapter does not claim to support Folia

Keep each callback very short · See the description in this section for the location

// Only update one count each time and decide whether to broadcast
seconds--;
boolean announce = seconds % 10 == 0 || seconds <= 5;
Checklist
workThe processing principles of this lesson
Send activity broadcastSynchronization tasks
Modify block or player statusSynchronization tasks
Large amounts of file or network I/ODo not include callbacks per second in this lesson
Ordinary Paper and FoliaThis lesson only applies to ordinary Paper

07 / 12

Blueprint of Activity Timer

The challenge provides /eventtimer start and /eventtimer stop. The console can also be operated, since server-wide activities do not require the operator to have a backpack. By default, only the OP has administrative rights, and ordinary players can only listen to the broadcast.

Blueprint for Activity Timer
  1. startThe administrator starts a round
  2. stopCancel current task
  3. Natural endBroadcast once and return to idle

Complete plugin.yml · Complete file

name: BlockAcademyL35
version: 1.0.0
main: de.teacherma.lesson35.EventTimerPlugin
api-version: '1.21.11'
author: TeacherMa
website: https://www.teacher-ma.de
commands:
  eventtimer:
    description: Manage classroom activity timers
    usage: /eventtimer <start|stop>
permissions:
  blockacademy.timer:
    default: op
  • Broadcast for 60 seconds at the beginning; then broadcast every 10 seconds, and broadcast every second for the last 5 seconds.
  • Repeating start does not create a second task; stop only cancels the current task.
  • The natural end is only broadcast once; it can be restarted after the end.

08 / 12

The first half of the activity timing program

The following two pages together are the complete EventTimerPlugin.java. First check the permissions and parameters, and then assign start and stop; the field active saves the common state. Enter eventtimer start on the console without the slash.

Activity timing program first half
  1. Entry CheckPermission and one parameter
  2. Start branchingFirst confirm that there is no activity
  3. Stop branchCancel and give truthful feedback

Main class part 1 · This paragraph 1/2, sequential connection

package de.teacherma.lesson35;

import java.util.Locale;
import java.util.Objects;
import net.kyori.adventure.text.Component;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.scheduler.BukkitTask;

public final class EventTimerPlugin extends JavaPlugin {
    private BukkitTask active;
    @Override
    public void onEnable() {
        Objects.requireNonNull(getCommand("eventtimer")).setExecutor(this);
    }
    @Override
    public boolean onCommand(CommandSender sender, Command command,
                             String label, String[] args) {
        if (!sender.hasPermission("blockacademy.timer")) {
            sender.sendMessage("Only active administrators can operate the timer");
            return true;
        }
        if (args.length != 1) {

Main Class Part 1·This paragraph 2/2, sequential connection

            sender.sendMessage("Usage: /eventtimer start or stop");
            return true;
        }
        switch (args[0].toLowerCase(Locale.ROOT)) {
            case "start" -> {
                if (active != null) sender.sendMessage("Activity is already timing");
                else startTimer();
            }
            case "stop" -> {
                if (active == null) sender.sendMessage("There is currently no activity");
                else {
                    stopTimer();
                    getServer().broadcast(Component.text("Event canceled"));
                }
            }
            default -> sender.sendMessage("Parameters can only be start or stop");
        }
        return true;
    }

09 / 12

The lower part of the activity timing program

Continue to the previous page. At the natural end, cancel in the callback and then clear active; both manual stop and plug-in deactivation call the same stopTimer. Three ending paths eventually return to idle.

Activity timing program lower half
  1. 60 to 1Only one deduction will be made for each callback
  2. Return to zeroBroadcast, cancel, clear
  3. DisableCall unified stopTimer

Main class part 2·sequentially connected to the same source file

    private void startTimer() {
        getServer().broadcast(Component.text("Activity starts, remaining 60 seconds"));
        active = new BukkitRunnable() {
            private int seconds = 60;
            @Override
            public void run() {
                seconds--;
                if (seconds <= 0) {
                    getServer().broadcast(Component.text("Time is up, the activity is over!"));
                    cancel();
                    active = null;
                    return;
                }
                if (seconds % 10 == 0 || seconds <= 5) {
                    getServer().broadcast(Component.text("Remaining " + seconds + " seconds"));
                }
            }
        }.runTaskTimer(this, 20L, 20L);
    }
    private void stopTimer() {
        if (active != null) active.cancel();
        active = null;
    }
    @Override
    public void onDisable() { stopTimer(); }
}

10 / 12

Check the beginning and end and start again

The timer is most likely to make mistakes at the boundary: seconds are deducted as soon as it is started, broadcast is finished twice, and it is still talking after stopping. Use the following table to check item by item and match the order in the log with the messages in the game.

Check start end and start again
  1. BeginningCannot lose one second immediately
  2. EndCannot broadcast repeatedly
  3. Start againOnly one new countdown
Checklist
TestExpected
Start again immediately after startThere is only one countdown
stop during operationCancel the message once, then be quiet
stop when idlePrompt that there is currently no activity
Let 60 seconds end completely50, 40, 30, 20, 10, 5 to 1, end
Start again after the endStart again from 60 seconds
Stop server during timingPlug-in cleaning task
Ordinary players startPermission prompt, no task

11 / 12

Expansion challenges and own acceptance records

Leave the source code, actual running results and a problem record. Explain it in your own words first, and then run the verification; where the results are different from the predictions, they are often the most worthy of discussion.

Expansion tasks and clearance review
  1. Wooden PickaxeDelay prompts take into account offline
  2. Iron PickaxeExplain the 10 second countdown
  3. Diamond PickaxeDay and night reminders can be started and stopped
  • Wooden Pickaxe: Use runTaskLater to prompt the player after 3 seconds, and no error will be reported when the player exits.
  • Iron Pickaxe: Make a 10-second countdown and explain where the first delay, interval, and end conditions are respectively.
  • Diamond Pickaxe: Make a day and night reminder that can be started and stopped to ensure that repeated starts do not overlap and are canceled when disabled.
  • Acceptance requirements: record six moments: start, remaining 1, end, manual cancellation, restart and stop. Make it clear that this lesson uses tick timing.
Checklist
I can complete it independentlyMasteredPractice again
Can distinguish milliseconds and ticks□□
Will save and cancel the task□□
Understand the boundaries of synchronization tasks□□

12 / 12

Leave the evidence for the next adventure

Divide "can compile", "number rules pass" and "actual performance of the game is correct" into three columns. Scenarios that are not running are written to be tested; when bugs are discovered, trigger conditions, expected, actual, minimum repairs, and retest results are recorded.

Your verification record
CategoryThe operation you selectedEvidence left behind
NormalA successful path for this lessonVersion and actual output
BorderThe moment before the end, the maximum value or the full backpackCompare item by item with contract
RejectWrong parameters, no permissions or irrelevant eventsThe feedback is clear and the status has not been changed by mistake.
  • Explain why each arrow in this lesson points from here to there; the parallel cards have no sequential meaning.
  • First change a rule, then modify the description and expectations at the same time, and retest with the same input.

TAKE IT WITH YOU

Take the lesson offline

The complete lesson, code, diagrams and exercises, in your preferred language.