Skip to main content

TaskKit Task Utilities

Introduction

A utility module combining tasks, time, delay listeners, timeout listeners, and more.

Usage scenarios

  • Timeout handling tasks
  • Timer simulation
  • Task scheduling
  • IO task handling
  • Delayed tasks

Consumption of Single Task

Used for some IO tasks, or tasks that should not block business threads.

  • code 3: execute task with CacheThreadPool.
  • code 7: execute task with virtual threads.
public void execute() {
TaskKit.execute(() -> {
log.info("CacheThreadPool consumer task");
});

TaskKit.executeVirtual(() -> {
log.info("Virtual consumer task");
});
}

TaskListener Task Monitoring Callback Interface

TaskListener is a callback interface for time-related task monitoring.

Usage scenarios

One-time delayed tasks, task scheduling, lightweight controllable delayed tasks, lightweight periodic DB-write helpers, and other extension scenarios.


TaskListener provides several methods. Only onUpdate is required; others can be overridden as needed.

MethodModifierDescription
onUpdateCallback
triggerUpdatedefaultWhether to trigger onUpdate() callback
onException(Throwable)defaultException callback. If exceptions are thrown while running triggerUpdate() or onUpdate(), this method catches them.
getExecutordefaultSpecify an executor for the above methods to avoid occupying business threads.

Method description

  • onUpdate: write business logic here.
  • triggerUpdate: true executes onUpdate; false does not.
  • onException: catches exceptions thrown by triggerUpdate or onUpdate. Useful for unified handling and isolation so tasks do not affect each other.
  • getExecutor: specify an executor to consume the current task and avoid occupying default business threads.
@Slf4j
public class MyTaskListener implements TaskListener {
@Override
public void onUpdate() {
... your code
}

@Override
public boolean triggerUpdate() {
return true;
}

@Override
public void onException(Throwable e) {
log.error(e.getMessage(), e);
}

@Override
public Executor getExecutor() {
// return TaskKit.getCacheExecutor();
return TaskKit.getVirtualExecutor();
}
}

OnceTaskListener Timeout and Delay Handling Tasks

Timeout handling and delayed handling, executed only once. Suitable for tasks without IO operations.

TypeParameter NameDescription
OnceTaskListenertaskListenerListener
longdelayDelay time
TimeUnitunitTime unit

Code description

  • code 2: execute once, after 2 seconds.
  • code 3: execute once, after 1 minute.
  • code 4: execute once, after 500 milliseconds.
  • code 15: execute once, after 1500 milliseconds; execute onUpdate only when theTriggerUpdate is true.
public void runOnce() {
TaskKit.runOnce(() -> log.info("2 Seconds"), 2, TimeUnit.SECONDS);
TaskKit.runOnce(() -> log.info("1 Minute"), 1, TimeUnit.MINUTES);
TaskKit.runOnce(() -> log.info("500 delayMilliseconds"), 500, TimeUnit.MILLISECONDS);

boolean theTriggerUpdate = RandomKit.randomBoolean();
TaskKit.runOnce(new OnceTaskListener() {
@Override
public void onUpdate() {
log.info("1500 delayMilliseconds");
}

@Override
public boolean triggerUpdate() {
return theTriggerUpdate;
}

}, 1500, TimeUnit.MILLISECONDS);
}

Comprehensive example exercise

This section uses a case to describe usage.

Business scenario:

Duration-based skill effects, or turn countdowns in board/card games such as Hearthstone-like games, Three Kingdoms Kill, Dou Dizhu, Mahjong, and similar games.

When it is a player's turn, the game UI usually shows a countdown. The player must finish within the time limit. A common approach is using a timer. If player action is completed in time, the timer must be cancelled.

The framework's TaskKit.runOnce can simulate a timer. This usage can make business code clearer. By extending OnceTaskListener, business requirements (such as timer cancellation) can be achieved, and this design better follows single responsibility.

In code, two classes are defined: Room and OperationTask.

  • Room is the current room class, storing match and player-related information. A round property is defined to record current round count (used to control whether timer executes). Whenever player operation completes, round changes (+1).
  • OperationTask is a timer-task listener class assisting business logic. Key logic is in triggerUpdate. Only when OperationTask.currentRound equals room.round does onUpdate trigger. This approach does not require explicitly cancelling timers, but controls execution through business logic.
public void test() {
Room room = new Room();
// start next round
room.startNextRound();
// start next round, previous task will not execute
room.startNextRound();
}

record OperationTask(int currentRound, Room room) implements OnceTaskListener {
@Override
public void onUpdate() {
room.notice();
}

@Override
public boolean triggerUpdate() {
return currentRound == room.round.get();
}
}

class Room {
AtomicInteger round = new AtomicInteger(1);
long currentOperationPlayerId;

void notice() {
this.startNextRound();
}

void startNextRound() {
int currentRound = this.round.incrementAndGet();
this.currentOperationPlayerId = 100;
TaskKit.runOnce(new OperationTask(currentRound, this), 1, TimeUnit.SECONDS);
}
}

IntervalTaskListener Interval Execution and Task Scheduling

This method is mainly used to simulate ScheduledThreadPoolExecutor. If tasks need interval execution (every N seconds/minutes/hours), this method can be used as a replacement.

Tasks can be consumed multiple times, execution can be controlled, and cancellation is supported.

TypeParameter NameDescription
IntervalTaskListenertaskListenerTask listener
longtickTick interval; callback is invoked once per tick interval
TimeUnittimeUnitTick time unit

It is similar to OnceTaskListener, so details are not repeated. Compared with OnceTaskListener, this interface adds isActive. When isActive returns false, it is removed from the scheduler.

IntervalTaskListener supports:

  • Task scheduling (interval and time unit)
  • Task removal
  • Task skip
  • Custom executor

  • code 2: invoke once every 2 seconds.
  • code 3: invoke once every 30 minutes.
public void runInterval() {
TaskKit.runInterval(() -> log.info("tick 2 Seconds"), 2, TimeUnit.SECONDS);
TaskKit.runInterval(() -> log.info("tick 30 Minute"), 30, TimeUnit.MINUTES);
}

  • code 12: returning false means inactive; current listener is removed from listener list.
public void runInterval() {
TaskKit.runInterval(new IntervalTaskListener() {
int hp = 2;

@Override
public void onUpdate() {
hp--;
}

@Override
public boolean isActive() {
return hp != 0;
}
}, 1, TimeUnit.SECONDS);
}

  • code 12: execute onUpdate only when return value is true.
public void runInterval() {
TaskKit.runInterval(new IntervalTaskListener() {
int hp;

@Override
public void onUpdate() {
// your code
}

@Override
public boolean triggerUpdate() {
hp++;
return hp % 2 == 0;
}
}, 1, TimeUnit.SECONDS);
}

  • code 12: specify executor to execute onUpdate callback, avoiding blocking other tasks.
public void runInterval() {
ExecutorService executorService = TaskKit.getCacheExecutor();

TaskKit.runInterval(new IntervalTaskListener() {
@Override
public void onUpdate() {
// your DB code
}

@Override
public Executor getExecutor() {
return executorService;
}
}, 1, TimeUnit.SECONDS);

}

Summary

TaskKit provides multiple task-consumption modes:

  1. execute series: task consumed once.
  2. runOnce series: task consumed once; supports delayed execution and cancellation.
  3. runInterval series: task consumed multiple times; execution can be controlled and cancellation is supported.