GUI以30 fps运行?

在测试一些使用Swingworker的实时仿真代码时,我注意到我的GUI似乎总是以30 fps运行,不多也不少。 每次用户与应用程序交互时(如鼠标移动)或调用Swingworker的process()方法时,我都会更新GUI。 Swingworker现在没有做任何事情,它只是从GUI抓取鼠标位置并通过publish()和process()方法将其作为克隆发回(我只是这样做,看看我能做什么,能做什么在线程之间进行通信时会这样做,因为multithreading对我来说仍然是一个新手。 我在任何地方都没有定时器,Swingworker的process()方法在GUI上调用repaint(),所以我想知道是什么原因导致GUI以30 fps更新? 是否可能默认情况下GUI中的vsync处于活动状态,或者它是Swingworker中process()方法的某些行为? 最后:有没有办法获得更高的帧速率?

这是一个表现出这种行为的sscce:

public class SimGameTest implements Runnable { public static void main(String[] args) { SwingUtilities.invokeLater(new SimGameTest()); } @Override public void run() { MainWindow mainWindow = new MainWindow(new Game()); mainWindow.setLocationRelativeTo(null); mainWindow.setVisible(true); } } public class MainWindow extends JFrame { private Game game; private GamePanel gamePanel; public MainWindow(Game game) { this.game = game; createAndShowGUI(); startGame(); } private void startGame() { GameSim gameSim = new GameSim(game, gamePanel); gameSim.execute(); } private void createAndShowGUI() { setTitle("Sim game test"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setResizable(false); JPanel contentPane = new JPanel(new GridBagLayout()); gamePanel = new GamePanel(game); contentPane.add(gamePanel); add(contentPane); pack(); } } public class Game { public Point mouseLocation = new Point(); public Point clonedMouseLocation = new Point(); } public class GameSim extends SwingWorker { private Game game; private GamePanel gamePanel; public GameSim(Game game, GamePanel gamePanel) { this.game = game; this.gamePanel = gamePanel; } @Override protected Point doInBackground() throws Exception { while (true) { publish((Point) game.mouseLocation.clone()); } } @Override protected void process(List pointList) { game.clonedMouseLocation = pointList.get(pointList.size() - 1); gamePanel.repaint(); } } public class GamePanel extends JPanel { private Game game; private long lastTime; public GamePanel(Game game) { this.game = game; setPreferredSize(new Dimension(512, 512)); addMouseMotionListener(new GamePanelListener();); } @Override public void paintComponent(Graphics g) { // draw background g.setColor(new Color(0, 0, 32)); g.fillRect(0, 0, getWidth(), getHeight()); g.setColor(new Color(192, 192, 255)); g.drawString(game.clonedMouseLocation.x + ", " + game.clonedMouseLocation.y, 10, 502); long now = System.nanoTime(); long timePassed = now - lastTime; lastTime = now; double fps = ((double) 1000000000 / timePassed); g.drawString("fps: " + fps, 10, 482); } private class GamePanelListener extends MouseInputAdapter { @Override public void mouseMoved(MouseEvent e) { if (contains(e.getPoint())) { game.mouseLocation = e.getPoint(); } } } } 

我创建了另一个版本,我只计算重新绘制GUI的次数并在屏幕上显示计数,它似乎以每秒30的速度增加,所以我猜fps计算不是问题。

事实certificate, SwingWorker使用具有该DELAYjavax.swing.TimerRunnable实例发布到EventQueue

 private static class DoSubmitAccumulativeRunnable extends AccumulativeRunnable implements ActionListener { private final static int DELAY = (int) (1000 / 30); ... } 

您可以获得更高的帧速率,但不能使用javax.swing.SwingWorker 。 您可以从源代码构建SwingWorker ,但最终会使用Runnable实例使线程饱和。 另一种方法是将模型平放并定期对其进行采样,如下所示。