Java多线程:通过方法引用分离tick与render的线程执行逻辑
问题描述
现有Java代码中,Looper类的run方法在同一线程中依次调用State类的tick()和render()抽象方法(二者均无参无返回值,由子类实现具体逻辑)。需求是创建两个独立线程分别执行tick和render方法,且不重复编写Looper类。已知C++支持函数指针,但Java不支持,尝试过定义无参无返回的函数式接口但不知如何运用。
原代码
Looper类
public class Looper implements Runnable { private final int SECOND = 1000000000; private final ResourceBundle res = ResourceBundle.getBundle("game_properties"); private final int FPS = Integer.parseInt(res.getString("FPS")); private final State menu; public Looper(State menu) { this.menu = menu; } @Override public void run() { long quanta = SECOND/FPS; long delta = 0; long last = System.nanoTime(); while (true) { long now = System.nanoTime(); delta += now - last; last = now; if (delta > quanta) { delta = 0; try { State.getState().tick(); //期望在一个Looper线程执行 State.getState().render(); //期望在另一个Looper线程执行 } catch(RuntimeException e) { System.out.println("Exception in Looper, Switched to Menu State"); State.setState(menu); } } } } }
Launcher类
public class Launcher { public static void main(String[] args) throws IOException { State menu = new MenuState(); State.setState(menu); Thread loopThread = new Thread(new Looper(menu)); State.getState().init(); loopThread.start(); } }
解决方案
核心思路是用函数式接口封装tick和render的执行逻辑,让Looper类接收不同的逻辑作为参数,从而复用同一个Looper创建不同职责的线程。
步骤1:定义无参无返回的函数式接口
可以自定义语义更清晰的接口,也可以直接用Java自带的Runnable,这里自定义一个贴合场景的:
@FunctionalInterface public interface StateAction { void execute(); }
步骤2:改造Looper类
修改构造方法,新增StateAction参数接收要执行的逻辑,同时保留menu用于异常处理:
public class Looper implements Runnable { private final int SECOND = 1000000000; private final ResourceBundle res = ResourceBundle.getBundle("game_properties"); private final int FPS = Integer.parseInt(res.getString("FPS")); private final State menu; private final StateAction action; // 新增:要执行的逻辑 // 改造构造方法,传入要执行的动作 public Looper(State menu, StateAction action) { this.menu = menu; this.action = action; } @Override public void run() { long quanta = SECOND/FPS; long delta = 0; long last = System.nanoTime(); while (true) { long now = System.nanoTime(); delta += now - last; last = now; if (delta > quanta) { delta = 0; try { action.execute(); // 执行传入的逻辑,不再硬编码tick或render } catch(RuntimeException e) { System.out.println("Exception in Looper, Switched to Menu State"); State.setState(menu); } } } } }
步骤3:修改Launcher启动两个线程
分别创建执行tick和render的Looper实例,启动独立线程:
public class Launcher { public static void main(String[] args) throws IOException { State menu = new MenuState(); State.setState(menu); State.getState().init(); // 创建执行tick的线程 Thread tickThread = new Thread(new Looper(menu, () -> State.getState().tick())); // 创建执行render的线程 Thread renderThread = new Thread(new Looper(menu, () -> State.getState().render())); tickThread.start(); renderThread.start(); } }
关键说明
- 用Lambda表达式实现
StateAction接口,代码更简洁(也可以用匿名内部类替代) - 同一个
Looper类可复用,只需传入不同的StateAction逻辑,即可实现不同线程的职责划分 - 注意线程安全:如果
tick和render操作共享State对象的状态,需确保操作是线程安全的(比如使用synchronized或并发容器)
内容的提问来源于stack exchange,提问作者zjschrage
相关产品推荐
相关产品推荐

