Java thread.sleep(1)睡眠时间超过1毫秒 [英] Java thread.sleep(1) sleeping longer than 1 ms

查看:97
本文介绍了Java thread.sleep(1)睡眠时间超过1毫秒的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用Java开发2D游戏.到目前为止,我已经设法将游戏设置为使用全屏独占模式,并在自定义线程中进行主动渲染.我决定使用的游戏循环是固定时间步长变量渲染类型.这种类型的游戏循环本应尽可能快地呈现设备可以处理的速度,对此我并不完全满意.因此,我尝试使用Thread.sleep()限制帧速率.

I'm trying to develop a 2D game using Java. So far I've managed to set up the game to use the full screen exclusive mode and to do active rendering in a custom thread. The game loop I've decided to use is of the type fixed time step variable rendering. This type of game loop is supposed to render as fast as possible as the device can handle, which I'm not entirely happy about. So I'm trying to limit the frame rate using Thread.sleep().

如果我关闭所有渲染,并仅在游戏循环中更新游戏,则Thread.sleep(1)成功睡眠大约1 ms.但是,如果打开渲染,有时Thread.sleep(1)的睡眠时间要长于1 ms,例如15 ms. 我通过添加/删除线条来打开/关闭渲染:

If I turn off all the rendering, and simply update the game in the game loop, Thread.sleep(1) sleeps successfully about 1 ms. However, if I turn on the rendering, sometimes Thread.sleep(1) sleeps way longer than 1 ms, like 15 ms. I'm turning on/off the rendering by adding/removing the lines:

BufferedImage drawImage = render(Math.min(1d, lag / TIME_PER_UPDATE));
drawToScreen(drawImage);

是什么导致线程睡眠时间太长?

What is causing the thread to sleep for too long?

这是我第一次在这些论坛上发帖,所以请告诉我我在发帖中做错了什么,或者这是重复的(我没有找到类似的发帖). /p>

This is my first time posting on these forums, so please, do tell me if I've done something wrong in my post, or if this is a duplicate (I've not managed to find a similar post).

import java.awt.Color;
import java.awt.DisplayMode;
import java.awt.Frame;
import java.awt.Graphics2D;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.RenderingHints;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;

public class Main implements KeyListener
{

    private static final long serialVersionUID = 1L;
    private boolean gameRunning = false;
    private final double UPDATE_RATE = 60;
    private final double TIME_PER_UPDATE = 1000000000 / UPDATE_RATE;
    private final int MAX_UPDATES_BEFORE_RENDERING = 5;
    private final int TARGET_FPS = 60;
    private int windowWidth;
    private int windowHeight;
    private GraphicsDevice graphicsDevice;
    private DisplayMode defaultDisplayMode;
    private Frame frame;
    private BufferStrategy bufferStrategy;
    private Player player;

    public Main()
    {
        GraphicsDevice[] screenDevices = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices();
        this.graphicsDevice = screenDevices[0];

        // This is later used to restore the original display mode when closing
        // the game
        defaultDisplayMode = this.graphicsDevice.getDisplayMode();

        frame = new Frame("GameTest");

        frame.setIgnoreRepaint(true);
        frame.setResizable(false);
        frame.setUndecorated(true);

        // Ensure that the user device supports full screen exclusive mode
        if (this.graphicsDevice.isFullScreenSupported())
        {
            graphicsDevice.setFullScreenWindow(frame);
        }

        windowWidth = frame.getWidth();
        windowHeight = frame.getHeight();

        frame.createBufferStrategy(2);

        bufferStrategy = frame.getBufferStrategy();

        // The frame receives keyboard event dispatched on the EDT-thread.
        frame.addKeyListener(this);

        initGame();

        // Starts the gameThread. The updating of the game state and rendering
        GameThread gameThread = new GameThread();
        gameThread.start();

    }

    private void initGame()
    {
        player = new Player(300, 300);
    }

    private class GameThread extends Thread
    {

        @Override
        public void run()
        {
            gameLoop();
        }
    }

    public static void main(String[] Args)
    {
        new Main();
    }

    private void gameLoop()
    {
        gameRunning = true;

        double lastStartTime = System.nanoTime();
        double startTime;
        double elapsedTime = 0;
        double lag = 0;
        double lastRenderTime;
        int updateCount = 0;

        while (gameRunning)
        {
            System.out.println("");
            System.out.println("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
            System.out.println("New Gameloop");
            System.out.println("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");

            startTime = System.nanoTime();
            elapsedTime = startTime - lastStartTime;
            lag += elapsedTime;

            updateCount = 0;

            while (lag >= TIME_PER_UPDATE && updateCount < MAX_UPDATES_BEFORE_RENDERING)
            {
                updateGameState();
                lag -= TIME_PER_UPDATE;
                updateCount++;
            }

            if (startTime - lastStartTime > TIME_PER_UPDATE)
            {
                lastStartTime = startTime - TIME_PER_UPDATE;
            }

            BufferedImage drawImage = render(Math.min(1d, lag / TIME_PER_UPDATE));
            drawToScreen(drawImage);
            lastRenderTime = System.nanoTime();

            double currentFPS = 1000000000d / (lastRenderTime - startTime);

            //Sleeps until target FPS is reached
            System.out.println("");
            System.out.println("Before sleeping");
            System.out.println("");
            System.out.println("Current FPS:");
            System.out.println(currentFPS);

            while (currentFPS > TARGET_FPS && (lastRenderTime - startTime) < TIME_PER_UPDATE)
            {

                //Lets the CPU rest
                Thread.yield();

                double beginSleepTime = System.nanoTime();

                try
                {

                    Thread.sleep(1);        

                } catch (Exception e)
                {
                    e.printStackTrace();
                }

                double endSleepTime = System.nanoTime();

                lastRenderTime = System.nanoTime();
                currentFPS = 1000000000d / (lastRenderTime - startTime);

                System.out.println("");
                System.out.println("--------------------------------");
                System.out.println("Sleeping");
                System.out.println("");
                System.out.println("Time slept in ms:");
                System.out.println("");
                System.out.println((endSleepTime - beginSleepTime) / 1000000d);
                System.out.println("");
                System.out.println("current FPS");
                System.out.println("");
                System.out.println(currentFPS);     
            }

            lastStartTime = startTime;
        }   
    }

    private void updateGameState()
    {
        player.update();
    }

    private void drawToScreen(BufferedImage drawImage)
    {
        try
        {
            Graphics2D g2d = (Graphics2D) bufferStrategy.getDrawGraphics();

            g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);

            g2d.clearRect(0, 0, windowWidth, windowHeight);
            g2d.setBackground(Color.BLACK);

            g2d.drawImage(drawImage, 0, 0, windowWidth, windowHeight, null);

            g2d.dispose();

            if (!bufferStrategy.contentsLost())
            {
                bufferStrategy.show();
            }

        } catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    private BufferedImage render(double delta)
    {
        BufferedImage drawImage = new BufferedImage(windowWidth, windowHeight, BufferedImage.TYPE_INT_ARGB);
        drawImage.createGraphics();
        Graphics2D g = (Graphics2D) drawImage.getGraphics();

        g.setBackground(Color.WHITE);
        g.clearRect(0, 0, windowWidth, windowHeight);

        //Render player
        g.setColor(Color.BLUE);
        g.fillRect((int) Math.round(player.getLocX() + delta * player.getSpeedX()), (int) Math.round(player.getLocY() + delta * player.getSpeedY()), 64, 64);

        g.dispose();

        return drawImage;
    }

    @Override
    public void keyPressed(KeyEvent keyEvent)
    {
        switch (keyEvent.getKeyCode())
        {

        case KeyEvent.VK_ESCAPE:
            graphicsDevice.setDisplayMode(defaultDisplayMode);
            System.exit(0);
            break;
        case KeyEvent.VK_A:
            player.setSpeedX(-player.getMoveSpeed());
            break;
        case KeyEvent.VK_D:
            player.setSpeedX(player.getMoveSpeed());
            break;
        case KeyEvent.VK_W:
            player.setSpeedY(-player.getMoveSpeed());
            break;
        case KeyEvent.VK_S:
            player.setSpeedY(player.getMoveSpeed());
            break;
        case KeyEvent.VK_SPACE:

            break;
        case KeyEvent.VK_LESS:

            break;
        case KeyEvent.VK_I:

            break;

        }
    }

    @Override
    public void keyReleased(KeyEvent keyEvent)
    {
        switch (keyEvent.getKeyCode())
        {
        case KeyEvent.VK_A:
            player.setSpeedX(0);
            break;
        case KeyEvent.VK_D:
            player.setSpeedX(0);
            break;
        case KeyEvent.VK_W:
            player.setSpeedY(0);
            break;
        case KeyEvent.VK_S:
            player.setSpeedY(0);
            break;
        case KeyEvent.VK_SPACE:

            break;
        case KeyEvent.VK_LESS:

            break;
        case KeyEvent.VK_I:

            break;
        }
    }

    @Override
    public void keyTyped(KeyEvent keyEvent)
    {

    }

    private class Player
    {
        protected double speedX;
        protected double speedY;
        protected double locX;
        protected double locY;
        protected double moveSpeed;

        public Player(int locX, int locY)
        {
            speedX = 0;
            speedY = 0;
            this.locX = locX;
            this.locY = locY;

            moveSpeed = 3d;
        }

        public void update()
        {
            locY +=  speedY;

            locX += speedX;
        }

        public void setSpeedX(double speedX)
        {
            this.speedX = speedX;
        }

        public void setSpeedY(double speedY)
        {
            this.speedY = speedY;
        }

        public double getSpeedX()
        {
            return speedX;
        }


        public double getSpeedY()
        {
            return speedY;
        }

        public double getLocX()
        {
            return locX;
        }

        public double getLocY()
        {
            return locY;
        }

        public double getMoveSpeed()
        {
            return moveSpeed;
        }   
    }
}

推荐答案

java中的sleep()方法将当前正在执行的线程(处于运行状态)休眠1 ms.

The sleep() method in java puts the currently executing thread (in the running state) to sleep for 1 ms.

1 ms之后,线程进入可运行状态(可以运行),现在它取决于调度程序何时从可运行状态获取线程并执行该线程(即运行状态).

After 1 ms the thread comes to runnable state (able to run), now it depends on the scheduler when to take the thread from the runnable state and execute it (i.e, running state).

因此,您可以假定线程在重新运行之前休眠至少1ms.

For this reason, you can assume that the thread sleeps for a minimum of 1ms before running again.

下图描述了不同的线程状态:

Below figure describes the different thread states:

这篇关于Java thread.sleep(1)睡眠时间超过1毫秒的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆