LibGDX中额外线程导致FPS下降的问题求助
问题分析与解决方案
你的问题核心有两个:
- 每帧在
render()里创建新线程+调用join():线程创建销毁的开销极大,而且join()会阻塞主线程(渲染线程),直接导致FPS暴跌,这是掉帧的根本原因。 - 把线程放构造函数后,线程跑完一次
while循环就终止了:Thread对象只能start()一次,终止后无法重启,所以你调用restart()只是重置了m,但线程已经停止工作,自然增量固定。
方案一:完全不用线程(推荐)
你的需求是右键长按增加质量,逻辑非常轻量,完全没必要开线程。直接利用render()每帧执行的特性,结合时间间隔控制增量即可,性能拉满还无线程问题:
步骤1:在Screen类中添加状态变量
private boolean isRightButtonHeld = false; private long lastMassIncrementTime = 0; private static final long INCREMENT_INTERVAL = 50; // 每50ms加一次质量,可调整速度
步骤2:在render()中处理输入与增量逻辑
@Override public void render(float delta) { // 处理右键按下事件:重置质量,标记长按状态 if (Gdx.input.isButtonJustPressed(Input.Buttons.RIGHT)) { isRightButtonHeld = true; MainScreen.m = 100000; lastMassIncrementTime = System.currentTimeMillis(); } // 处理右键松开事件:创建行星,取消长按状态 else if (Gdx.input.isButtonJustReleased(Input.Buttons.RIGHT)) { isRightButtonHeld = false; planets.add(new Planet(10, MainScreen.m, mouseOnWorld2.x, mouseOnWorld2.y)); } // 长按期间按固定间隔增量 if (isRightButtonHeld) { long currentTime = System.currentTimeMillis(); if (currentTime - lastMassIncrementTime >= INCREMENT_INTERVAL) { MainScreen.m += 100; System.out.println(MainScreen.m); lastMassIncrementTime = currentTime; } } // 你的其他渲染逻辑... }
方案二:如果一定要用线程(正确写法)
如果坚持要用线程,必须用单个持久线程,通过标志位控制工作状态,避免重复创建线程,同时解决线程安全与空循环问题:
步骤1:改造IncrementMass线程
public class IncrementMass extends Thread { // volatile保证多线程下状态可见性 private volatile boolean running = false; private volatile boolean needReset = false; private static final long SLEEP_MS = 50; // 休眠避免空循环占用CPU @Override public void run() { while (!isInterrupted()) { synchronized (this) { // 未激活时等待通知,避免空跑 while (!running) { try { wait(); } catch (InterruptedException e) { // 线程被中断,直接退出 return; } } // 重置质量 if (needReset) { MainScreen.m = 100000; needReset = false; } } // 右键按住时增量 if (Gdx.input.isButtonPressed(Input.Buttons.RIGHT)) { // 同步共享变量读写,避免线程安全问题 synchronized (IncrementMass.class) { MainScreen.m += 100; System.out.println(MainScreen.m); } try { Thread.sleep(SLEEP_MS); } catch (InterruptedException e) { return; } } else { // 松开右键,停止工作 synchronized (this) { running = false; } } } } // 启动增量(右键按下时调用) public synchronized void startIncrement() { needReset = true; running = true; notify(); // 唤醒等待的线程 } // 停止增量(右键松开时调用) public synchronized void stopIncrement() { running = false; } }
步骤2:在Screen中使用线程
private IncrementMass incrementMass; // 在Screen构造函数中初始化线程(仅执行一次) public MainScreen() { incrementMass = new IncrementMass(); incrementMass.setDaemon(true); // 设置为守护线程,程序退出时自动销毁 incrementMass.start(); } @Override public void render(float delta) { // 处理右键按下 if (Gdx.input.isButtonJustPressed(Input.Buttons.RIGHT)) { incrementMass.startIncrement(); } // 处理右键松开 else if (Gdx.input.isButtonJustReleased(Input.Buttons.RIGHT)) { incrementMass.stopIncrement(); // 同步获取最新质量值 long currentMass; synchronized (IncrementMass.class) { currentMass = MainScreen.m; } planets.add(new Planet(10, currentMass, mouseOnWorld2.x, mouseOnWorld2.y)); } // 你的其他渲染逻辑... } // 屏幕销毁时中断线程 @Override public void dispose() { incrementMass.interrupt(); }
内容的提问来源于stack exchange,提问作者eisa.exe
相关产品推荐
相关产品推荐

