为事件循环类游戏开发带优先级队列的单线程Executor
实现建议:自定义分层队列+手动单线程事件循环
针对你的需求,JDK自带的Executor框架无法直接满足所有规则(尤其是Hard任务入队清空其他任务、Normal任务优先时完全忽略Soft任务的逻辑),最适合的方案是手动实现单线程事件循环,配合三个分层的任务队列,比基于Executor扩展更灵活可控。
核心思路
维护三个独立的线程安全队列,分别对应Soft、Normal、Hard任务,单线程循环按以下优先级顺序处理:
- 优先处理Hard任务:只要Hard队列有任务,先清空Soft和Normal队列,然后执行Hard任务(自然阻塞线程直到玩家完成操作)
- 无Hard任务时,处理Normal队列:只执行Normal任务,完全跳过Soft任务
- 无Normal任务时,再处理Soft队列
代码示例(Java)
// 定义任务优先级枚举 enum TaskPriority { SOFT, NORMAL, HARD } // 游戏任务抽象类 abstract class GameTask { final TaskPriority priority; GameTask(TaskPriority priority) { this.priority = priority; } abstract void execute(); } // 单线程事件循环实现 public class GameEventLoop extends Thread { private final BlockingQueue<GameTask> softQueue = new LinkedBlockingQueue<>(); private final BlockingQueue<GameTask> normalQueue = new LinkedBlockingQueue<>(); private final BlockingQueue<GameTask> hardQueue = new LinkedBlockingQueue<>(); private volatile boolean isRunning = true; // 外部提交任务的入口方法 public void submitTask(GameTask task) { switch (task.priority) { case SOFT -> softQueue.offer(task); case NORMAL -> normalQueue.offer(task); case HARD -> hardQueue.offer(task); } } @Override public void run() { while (isRunning) { // 1. 优先处理Hard任务 GameTask hardTask = hardQueue.poll(); if (hardTask != null) { // 清空所有低优先级任务队列 softQueue.clear(); normalQueue.clear(); // 执行Hard任务,线程会阻塞直到玩家操作完成 hardTask.execute(); continue; } // 2. 处理Normal任务 GameTask normalTask = normalQueue.poll(); if (normalTask != null) { normalTask.execute(); continue; } // 3. 处理Soft任务 GameTask softTask = softQueue.poll(); if (softTask != null) { softTask.execute(); continue; } // 无任务时休眠,避免CPU空转 try { Thread.sleep(10); } catch (InterruptedException e) { Thread.currentThread().interrupt(); isRunning = false; } } } // 停止事件循环的方法 public void shutdown() { isRunning = false; this.interrupt(); } }
关键细节说明
- 线程安全:使用
LinkedBlockingQueue保证多线程提交任务时的线程安全,消费端仅单线程处理,无需额外加锁。 - Hard任务阻塞:只要
GameTask的execute()方法内部实现阻塞逻辑(比如调用Object.wait()等待玩家触发唤醒,或者UI库的阻塞对话框),单线程会自然停在该任务上,直到玩家操作完成。 - 灵活性:手动事件循环可以轻松扩展其他规则(比如任务超时、批量处理等),比依赖Executor的黑盒封装更适配游戏场景。
备选方案:扩展ThreadPoolExecutor(不推荐)
如果一定要基于Executor框架实现,可以自定义BlockingQueue并重写offer()方法:当添加Hard任务时,先清空队列中所有Soft/Normal任务,同时队列的排序逻辑保证Hard>Normal>Soft。但这种方式需要处理ThreadPoolExecutor的内部锁机制,逻辑复杂且灵活性不足,仅适合必须依赖Executor的场景。
内容的提问来源于stack exchange,提问作者Fraser
相关产品推荐
相关产品推荐

