Java sleep()导致JFrame在调整大小时闪烁

Java sleep()导致JFrame在调整大小时闪烁,java,multithreading,swing,loops,jpanel,Java,Multithreading,Swing,Loops,Jpanel,所以我有一个我正在尝试制作的游戏,在游戏循环中,我调用Thread.sleep()。除此之外,我还有一些代码,可以在调整窗口大小时保持窗口的纵横比。这很好用,除了我在调整大小时会出现奇怪的闪烁。我已经将问题缩小到Thread.sleep(),当我取出这一行时,我的程序就像预期的那样工作,但这会导致CPU的峰值如此之高,以至于在我的Macbook上,活动监视器应用程序说我的游戏正在使用170%+!这是有问题的,也是我为什么把睡眠线放在那里的原因。我听说睡在事件调度线程上会导致这种效果,但我正在一个

所以我有一个我正在尝试制作的游戏,在游戏循环中,我调用Thread.sleep()。除此之外,我还有一些代码,可以在调整窗口大小时保持窗口的纵横比。这很好用,除了我在调整大小时会出现奇怪的闪烁。我已经将问题缩小到Thread.sleep(),当我取出这一行时,我的程序就像预期的那样工作,但这会导致CPU的峰值如此之高,以至于在我的Macbook上,活动监视器应用程序说我的游戏正在使用170%+!这是有问题的,也是我为什么把睡眠线放在那里的原因。我听说睡在事件调度线程上会导致这种效果,但我正在一个新线程中运行这个循环,所以我认为我很好。你们知道会发生什么吗?以下是部分源代码(您确实需要查看run()方法):


如果你们能帮我,我会喜欢的,我真的很难受。谢谢

您应该使用而不是线程来异步操作Swing组件。当我发现这个家伙时,我的生活改变了。SwingWorker为您提供了一个方法“process”,您可以使用它逐步执行操作,并提供了一个“done”方法来完成处理,这两种方法都可以安全地处理事件分派线程。您应该在“doInBackground”上执行的后台进程。

调用“Thread.sleep(n)”会导致整个线程变得无响应,如果此线程与JFrame线程绑定,则该线程也会变得无响应,并导致整个帧和组件冻结并停止响应——这可能是闪烁的原因。因此,确保睡眠在游戏循环中,而不是在帧上,一种方法是在初始化时创建两个线程,一个用于帧,另一个用于逻辑,然后让游戏循环处理输入和输出,而显示线程只是显示(我相信这是大多数游戏引擎的工作方式)。另外,请确保任何线程都没有链接,否则休眠线程将影响显示线程。

我找到了问题的答案。调用循环的类是一个JPanel,在调整大小时没有重新绘制,只有当循环告诉它时才重新绘制,这导致了一些JPanel没有被绘制的时期。我通过重写paintComponent解决了这个问题。

如果使用Thread.sleep,你可以让整个程序休眠,但是如果你让游戏循环扩展线程,然后调用GameLoop.sleep(),它应该可以工作。编辑:不应该工作,因为你只需再次调用Thread.sleep,可能会想到…@redxef我怎么能只睡循环线程?我的意思是,你可以为游戏循环使用第二个线程,但如果你扩展线程,你只需再次调用super方法,因此不起作用。还可以尝试在睡眠调用中使用非常小的数字,一毫秒或两毫秒就可以了。大多数情况下,这足以使处理器尽可能快地停止运行循环,但仍然足够短,因此您不会注意到暂停。。。如果游戏线程对JFrame或其运行中的线程有任何影响,或者它们通过线程链接进行链接,那么以每秒60帧或60个循环的速度运行应该是一个神奇的数字。这就是为什么框架在它自己的独立线程中运行是很常见的。
package jeffrey_ryan.game2d;

public class GameLoop implements Runnable {
    private boolean running = false;
    private boolean paused = false;
    private float gameHertz = 30.0f;
    private long timeBetweenUpdates = (long) (1_000_000_000 / gameHertz);
    private int maxUpdates = 5;
    private LoopListener loopListener;

    public void run() {
        long lastUpdateTime = System.nanoTime();
        running = true;

        while (running) {
            long now = System.nanoTime();
            if (!paused) {
                int updates = 0;

                while (now - lastUpdateTime >= timeBetweenUpdates && updates < maxUpdates) {
                    if (loopListener != null) {
                        loopListener.update((double) timeBetweenUpdates / 1_000_000_000);
                    }

                    lastUpdateTime += timeBetweenUpdates;
                    updates++;
                }

                if (loopListener != null) {
                    float interpolation = Math.min(1.0f, (float) (now - lastUpdateTime) / timeBetweenUpdates);
                    loopListener.render(interpolation);
                }

                long timeRemaining = (timeBetweenUpdates - (now - lastUpdateTime)) / 1_000_000;

                try {
                    Thread.sleep(Math.max(timeRemaining - 5, 0)); // HERE'S THE OFFENDING LINE ******************
                }
                catch (InterruptedException ie) {
                    ie.printStackTrace();
                }
            }
            else {
                try {
                    Thread.sleep(25);
                }
                catch (InterruptedException ie) {
                    ie.printStackTrace();
                }
            }
        }
    }

    public void start() {
        running = true;
    }

    public void stop() {
        running = false;
    }

    public void pause() {
        paused = true;
    }

    public void play() {
        paused = false;
    }

    public float getSpeed() {
        return gameHertz;
    }

    public void setSpeed(float hertz) {
        gameHertz = hertz;
        timeBetweenUpdates = (long) (1_000_000_000 / gameHertz);
    }

    public int getMaxUpdates() {
        return maxUpdates;
    }

    public void setMaxUpdates(int updates) { 
        maxUpdates = updates;
    }

    public void setLoopListener(LoopListener listener) {
        loopListener = listener;
    }
}
@Override
public void addNotify() {
    super.addNotify();

    addKeyListener(this);
    addMouseListener(this);

    Thread thread = new Thread(loop, "GameLoop");
    thread.start();
}