
Folia多线程支持揭秘Towny如何用TaskScheduler抽象实现分区并发【免费下载链接】TownyTowny Advanced Minecraft plugin for Bukkit/Spigot.项目地址: https://gitcode.com/gh_mirrors/to/TownyTowny 是一款功能强大的 Minecraft 服务器插件用于在 Bukkit/Spigot/Paper/Folia 环境中管理城镇、国家与领地保护。本文深入揭秘 Towny 如何面向 Folia 实现多线程分区并发通过自定义的 TaskScheduler 抽象接口一套代码同时兼容单线程 Bukkit、多线程 Paper 和分区并发 Folia 三种服务器运行时。为什么需要 Folia 多线程支持 传统 Bukkit/Spigot 服务器所有逻辑都跑在唯一的主线程上玩家越多、插件越多主线程就越容易卡顿。Folia 将世界切分为多个 Region 分区每个分区由独立线程并发处理——理论上性能可以随 CPU 核心数线性提升。但对插件开发者来说这是噩梦过去可以随意在事件监听器里访问全局数据在 Folia 中必须保证只操作自己分区内的实体和方块任务必须投递到正确的线程执行。一个接口统一三种调度器TaskScheduler 抽象Towny 的解法是在providers/BaseProviders模块中定义了一对与具体服务器实现无关的接口TaskScheduler[providers/BaseProviders/src/main/java/com/palmergames/bukkit/towny/scheduling/TaskScheduler.java]定义了run、runLater、runRepeating、runAsync以及runGlobal系列方法并额外提供了isGlobalThread()、isTickThread()、isEntityThread(Entity)、isRegionThread(Location)四个线程判断方法ScheduledTask同目录下的 [ScheduledTask.java]封装了cancel()、isCancelled()、isCurrentlyRunning()等任务状态查询关键的 API 设计是按目标调度的重载方法run(location, task)—— 把任务投递到该坐标所属分区的线程run(entity, task)—— 把任务投递到该实体所属分区的线程runAsync(task)—— 投递到任意异步线程插件主代码只需要依赖这层接口就彻底告别了对BukkitScheduler的硬绑定。启动时自动探测运行时零配置 ✅在插件主类 [Towny/src/main/java/com/palmergames/bukkit/towny/Towny.java] 中Towny 通过类是否存在来判断运行环境并在构造器中完成调度器选择this.scheduler isFolia() ? new FoliaTaskScheduler(this) : expandedSchedulingAvailable() ? new PaperTaskScheduler(this) : new BukkitTaskScheduler(this);Folia 环境使用FoliaTaskScheduler对接 RegionScheduler / GlobalRegionScheduler / AsyncScheduler 三个 Folia 调度器Paper 环境使用PaperTaskScheduler继承自 Folia 实现复用扩展调度 API纯 Bukkit 环境退化为经典BukkitTaskScheduler行为与原始 BukkitScheduler 一致三个实现分别位于providers/BaseProviders、providers/PaperProvider、providers/FoliaProvider模块通过 Maven 多模块结构按需加载。分区并发的核心细节 1. 线程归属判断FoliaTaskScheduler中isRegionThread(location)通过isOwnedByCurrentRegion(location)判断当前线程是否就是目标坐标所在的分区线程。这让 Towny 的代码可以如果已在正确线程就直接执行否则再投递任务避免了不必要的调度开销。2. 无目标的同步任务降级为异步一个容易被忽视的细节Folia 中不存在全局主线程。因此FoliaTaskScheduler.run(task)在没有位置/实体上下文时会直接转发到runAsync——因为在 Folia 中普通同步逻辑本身就应该跑在异步线程里不占用任何分区线程。而PaperTaskScheduler则重写了这些方法让同样的调用在 Paper 上走globalRegionScheduler同步执行保证语义一致同一段业务代码在 Folia 上并发执行在 Paper 上串行执行开发者无需关心差异。3. 任务句柄的统一封装FoliaScheduledTask[providers/FoliaProvider/.../FoliaScheduledTask.java]将 Folia 的任务句柄包装成统一接口把 Folia 特有的ExecutionState枚举翻译成通用的isCurrentlyRunning()使任务取消、状态查询逻辑在三端完全复用。这套抽象带来的实际效果 60 个使用点从每日税收任务tasks/DailyTimerTask.java、地图渲染object/CellSurface.java、玩家登录tasks/OnPlayerLogin.java到 HUD 更新huds/HUDManager.java全项目统一通过getScheduler()获取调度器HUD 同样分端处理HUDManager根据isFolia()选择FoliaHUD或PaperHUD保证计分板更新在正确的分区线程上执行一套代码三端运行插件作者在写功能时只需问自己这个操作属于哪个位置/实体调度细节由抽象层兜底总结Towny 的 Folia 支持并非简单的 API 替换而是通过TaskScheduler接口抽象出按位置调度、按实体调度、异步调度、全局调度四类语义再用三个实现分别落地到 Folia / Paper / Bukkit。这套接口 环境探测 分端实现的模式正是所有希望在 Folia 时代保持高性能的 Minecraft 插件值得借鉴的分区并发实践。【免费下载链接】TownyTowny Advanced Minecraft plugin for Bukkit/Spigot.项目地址: https://gitcode.com/gh_mirrors/to/Towny创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考