Skip to content

调度器(任务调度)

概述

Bngeuit 提供内置的任务调度器,支持同步和异步两种任务模式:

  • 同步任务runSync):在专用单线程 scheduler-sync 上串行执行,任务之间天然线程安全
  • 异步任务runAsync):在线程池 scheduler-async(4 线程)中并发执行,适合 I/O 密集型操作

所有延迟/周期参数单位为毫秒

快速上手

获取调度器

java
import cn.org.bukkit.bngeuit.Bngeuit;
import cn.org.bukkit.bngeuit.scheduler.BngeuitScheduler;

BngeuitScheduler scheduler = Bngeuit.getScheduler();

立即执行

java
// 同步任务(与事件处理串行,线程安全)
scheduler.runSync(plugin, () -> {
    // 直接操作游戏状态,无需加锁
    System.out.println("同步执行");
});

// 异步任务(线程池并发)
scheduler.runAsync(plugin, () -> {
    // 适合网络请求、文件 I/O 等
    String result = httpGet("https://api.example.com/data");
});

延迟执行

java
// 5 秒后同步执行
scheduler.runSyncLater(plugin, () -> {
    Bngeuit.sendGroupText(groupOpenid, 1, "延迟消息");
}, 5000);

// 3 秒后异步执行
scheduler.runAsyncLater(plugin, () -> {
    // 异步 I/O 操作
}, 3000);

定时任务

java
// 每 60 秒执行一次(首次延迟 10 秒)
scheduler.runSyncTimer(plugin, () -> {
    Bngeuit.sendGroupText(groupOpenid, 1, "定时消息");
}, 10000, 60000);

// 每 5 分钟异步轮询
scheduler.runAsyncTimer(plugin, () -> {
    checkAndProcessQueue();
}, 0, 300000);

取消任务

java
import cn.org.bukkit.bngeuit.scheduler.BngeuitTask;

// 保存任务句柄
BngeuitTask task = scheduler.runSyncTimer(plugin, () -> { ... }, 0, 60000);

// 取消单个任务
task.cancel();
// 或通过 ID 取消
scheduler.cancel(task.getTaskId());

// 取消插件的所有任务
scheduler.cancelTasks(plugin);

查询任务

java
import java.util.List;

List<BngeuitTask> tasks = scheduler.getActiveTasks(plugin);
for (BngeuitTask t : tasks) {
    System.out.printf("任务 #%d [%s] 已取消: %s%n",
        t.getTaskId(), t.isSync() ? "同步" : "异步", t.isCancelled());
}

API 参考

BngeuitScheduler

任务调度器接口。

任务提交

方法说明
runSync(owner, task)立即同步执行
runSyncLater(owner, task, delayMs)延迟同步执行
runSyncTimer(owner, task, delayMs, periodMs)定时同步执行
runAsync(owner, task)立即异步执行
runAsyncLater(owner, task, delayMs)延迟异步执行
runAsyncTimer(owner, task, delayMs, periodMs)定时异步执行

参数说明:

  • owner:提交任务的插件(null 表示系统任务)
  • task:要执行的 Runnable
  • delayMs:首次执行延迟(毫秒)
  • periodMs:重复间隔(毫秒)

任务管理

方法说明
cancel(taskId)按 ID 取消任务
cancelTasks(plugin)取消指定插件的所有任务(插件卸载时自动调用)
getActiveTasks(plugin)查询指定插件的活跃任务列表
shutdown()关闭调度器(取消所有任务,关闭线程池)

BngeuitTask

任务句柄接口。

方法返回类型说明
getTaskId()int全局唯一任务 ID
getOwner()Plugin提交任务的插件(系统任务为 null
isSync()boolean是否为同步任务
isCancelled()boolean是否已取消或已完成
cancel()void取消任务(不会中断正在执行的任务)

同步 vs 异步

特性同步任务异步任务
执行线程专用单线程 scheduler-sync 串行线程池 scheduler-async(4 线程)并发
线程安全任务之间天然串行安全需自行处理同步
适用场景需要顺序执行的定时任务网络请求、文件 I/O
阻塞影响阻塞后续 sync 任务不影响 sync 线程

注意

同步任务在独立的 scheduler-sync 线程上执行,与事件处理线程不同。但 sync 任务之间是串行的,长时间运行的 sync 任务会阻塞后续 sync 任务。与事件处理线程之间仍需注意并发安全。

插件卸载

插件卸载时,框架自动调用 cancelTasks(plugin) 清理该插件的所有任务。无需手动清理。

系统任务(owner == null)不受插件卸载影响。

完整示例

java
import cn.org.bukkit.bngeuit.Bngeuit;
import cn.org.bukkit.bngeuit.scheduler.*;
import cn.org.bukkit.bngeuit.event.SubscribeEvent;
import cn.org.bukkit.bngeuit.event.receive.GroupAtMessageEvent;

public class SchedulerExample {

    private BngeuitTask heartbeatTask;

    // 启动心跳定时任务
    public void startHeartbeat(Plugin plugin, String groupOpenid) {
        BngeuitScheduler scheduler = Bngeuit.getScheduler();

        heartbeatTask = scheduler.runSyncTimer(plugin, () -> {
            Bngeuit.sendGroupText(groupOpenid, 1, "机器人在线 ✓");
        }, 0, 300000); // 每 5 分钟
    }

    // 停止心跳
    public void stopHeartbeat() {
        if (heartbeatTask != null) {
            heartbeatTask.cancel();
        }
    }

    // 异步请求示例
    @SubscribeEvent
    public void onCommand(GroupAtMessageEvent e) {
        Plugin plugin = ...; // 获取当前插件
        BngeuitScheduler scheduler = Bngeuit.getScheduler();

        // 异步获取数据,完成后直接发送消息
        scheduler.runAsync(plugin, () -> {
            String data = fetchDataFromAPI();
            // API 方法本身是线程安全的,无需切回 sync 线程
            Bngeuit.replyGroupText(e.getGroupOpenid(), e.getId(), 1, data);
        });
    }
}