Java 代码有时可以工作,但其他代码不能工作(内存或线程问题)

Java 代码有时可以工作,但其他代码不能工作(内存或线程问题),java,multithreading,swing,Java,Multithreading,Swing,我有一个奇怪的问题,我不知道是什么原因造成的。有时,问题甚至不存在。据我猜测,这是一个Java内存问题或某种线程问题 我有一艘飞船,飞船射出子弹如果我按下空格键,飞船就会射出子弹。我让子弹每200毫秒发射一次。有时他们射门很好,移动速度也一样!其他时候,它们以不同的速度射击。这是什么原因造成的 package JGame.Actions; import JGame.GameObject.GameObject; import javax.swing.AbstractAction; public

我有一个奇怪的问题,我不知道是什么原因造成的。有时,问题甚至不存在。据我猜测,这是一个Java内存问题或某种线程问题

我有一艘
飞船
,飞船射出
子弹
如果我按下空格键,飞船就会射出子弹。我让子弹每200毫秒发射一次。有时他们射门很好,移动速度也一样!其他时候,它们以不同的速度射击。这是什么原因造成的

package JGame.Actions;

import JGame.GameObject.GameObject;
import javax.swing.AbstractAction;

public class MoveAction extends Action implements Runnable{

    protected GameObject obj;
    protected int endX = 0, endY = 0;
    protected int moveAmount = 0;
    protected Thread thread;

    public void moveToY(GameObject obj, int y, int amount, AbstractAction complete){
        this.obj = obj;
        this.endY = y;
        this.moveAmount = amount;
        this.complete = complete;
        thread = new Thread(this);
        thread.start();
    }

    public void run(){
        try{
            boolean run = true;
            while(run){
                int objY = obj.getY();
                if(objY > this.endY){
                    obj.setY(obj.getY() - 1);
                }else if(objY < this.endY){
                    obj.setY(obj.getY() + 1);
                }else{
                    run = false;
                    this.actionComplete();
                }
                thread.sleep(moveAmount);
            }
        }catch(Exception e){
        }
    }
}
在我的代码中,我调用
moveToY
这是一个非常简单的调用,但有时
子弹
以不同的速度移动(错误),而其他子弹则以相同的速度移动(正确)。我不知道这是否有助于提到,当子弹移动时,有时它们会减速一两秒钟,然后再加速到正确的速度

编辑:主线程 下面是我使用paintComponent的主要线程

@Override
public void run(){
    try{
        while(true){
            // Check for key press events
            Iterator actions = KeyboardMap.map.entrySet().iterator();
            while(actions.hasNext()){
                Map.Entry ap = (Map.Entry)actions.next();
                Mapping mp = (Mapping)ap.getValue();
                if(mp.pressed){
                    mp.run();
                }
            }

            // Check for click mouse events
            Iterator actions2 = MouseMap.map.entrySet().iterator();
            while(actions2.hasNext()){
                Map.Entry ap = (Map.Entry)actions2.next();
                Mapping mp = (Mapping)ap.getValue();
                if(mp.pressed){
                    mp.run();
                }
            }

            for(GameObject go : gameObjects){
                if(!go.getLeaveScreen()){
                    int goWidth = go.getWidth();
                    int goHeight = go.getHeight();
                    int goX = go.getX();
                    int goY = go.getY();
                    int gameWidth = Game.width;
                    int gameHeight = Game.height;
                    if(goX + goWidth >= gameWidth){
                        go.setX(gameWidth - goWidth);
                    }
                    if(goX <= 0){
                        go.setX(0);
                    }
                    if(goY + goHeight >= gameHeight){
                        go.setY(gameHeight - goHeight);
                    }
                    if(goY <= 0){
                        go.setY(0);
                    }
                }
            }
            this.repaint();
            Thread.sleep(roomSpeed);
        }
    }catch(Exception e){
    }
}

public void paintComponent(Graphics g){
    try{
        g.drawImage(bg, 0, 0, this);
        for(int i = 0; i < gameObjects.size(); i++){
            GameObject go = gameObjects.get(i);
            g.drawImage(go.getSprite(), go.getX(), go.getY(), this);
        }
    }catch(Exception e){
    }
}
@覆盖
公开募捐{
试一试{
while(true){
//检查按键事件
迭代器操作=KeyboardMap.map.entrySet().Iterator();
while(actions.hasNext()){
Map.Entry ap=(Map.Entry)actions.next();
映射mp=(映射)ap.getValue();
如果(按mp键){
mp.run();
}
}
//检查单击鼠标事件
迭代器动作2=MouseMap.map.entrySet().Iterator();
while(actions2.hasNext()){
Map.Entry ap=(Map.Entry)actions2.next();
映射mp=(映射)ap.getValue();
如果(按mp键){
mp.run();
}
}
用于(游戏对象转到:游戏对象){
如果(!go.getLeaveScreen()){
int goWidth=go.getWidth();
int goHeight=go.getHeight();
int goX=go.getX();
int goY=go.getY();
int gameWidth=Game.width;
int gameHeight=Game.height;
如果(goX+goWidth>=gameWidth){
go.setX(gameWidth-goWidth);
}
如果(goX=游戏高度){
go.setY(游戏高度-goHeight);
}

如果(goY好吧,我猜您有大量并发线程在运行(一个通过移动bullet),并且您希望每个线程在
moveAmount
毫秒后醒来。您不能有这样的保证,因为线程调度程序允许每个线程一次运行一段时间,因此您可能会出现故障


另一个问题是,您似乎在事件分派线程之外对Swing组件执行修改,这显然是被禁止的。

好吧,我猜您有大量并发线程正在运行(一个是通过移动bullet),并且您希望每个线程在
moveAmount
毫秒后完全唤醒。您不能有这样的保证,因为线程调度程序允许每个线程一次运行一段时间,因此您可能会出现故障


另一个问题是,您似乎在事件调度线程之外执行对Swing组件的修改,这显然是被禁止的。

告知您自己多线程的使用情况以及如何正确制作游戏的处理结构。
对于您的案例来说,最重要的信息是:您应该只使用一个线程来处理/移动所有子弹,然后进行渲染。

了解多个线程的用法以及如何正确制作游戏的处理结构。
对于您的案例,最重要的信息是:您应该只使用一个线程来处理/移动所有项目符号,然后进行渲染。

代码中最重要的更改是不要使用
线程对时间建模。睡眠
。使用摆动计时器,您将计划执行每个
移动量
milliseconds,作为奖励,代码在事件调度线程上执行,您无需付出任何努力。

代码中最重要的更改是不要使用
线程对时间建模。睡眠
。使用摆动计时器,您将计划每隔
moveAmount
毫秒执行一次另外,代码是在事件调度线程上执行的,您无需付出任何努力。

+1对于JBNizet,我建议重新构建您的游戏循环以更新实体移动等,这样您就不必通过其他线程执行此操作,因此单个线程将处理屏幕上所有实体的移动等。请参阅此固定时间步长的游戏循环示例:完全正确。一个循环来控制所有实体。+1到JBNizet,我建议重新构建游戏循环来更新实体移动等,这样你就不必通过其他线程来完成这项工作,因此一个线程将处理屏幕上所有实体的移动等。请参阅此固定时间步游戏循环示例:完全正确。一个循环来控制所有实体。具体取决于游戏对象是,即如果它是JComponent,EDT将应用,如果不是,即OP使用扩展的矩形/形状类,则不需要Swing timer,因为更改形状/矩形的坐标不会修改任何Swing UI组件。无论是否需要EDT,这仍然是所有其他原因的解决方法。如果没有Swing组件正在使用我认为执行不必要的代码(不修改Swing组件的代码)在EDT中,a是不正确的,它应该被很好地使用,因为你没有考虑到,通过这种方法,有一个全新的资源需要管理——而且是浪费,如果所涉及的计算不会给EDT带来真正的负担。根据游戏对象是什么,例如,如果它是JComponent,EDT将被应用,如果不是,例如,OP使用扩展的矩形/形状类t韩秋千
@Override
public void run(){
    try{
        while(true){
            // Check for key press events
            Iterator actions = KeyboardMap.map.entrySet().iterator();
            while(actions.hasNext()){
                Map.Entry ap = (Map.Entry)actions.next();
                Mapping mp = (Mapping)ap.getValue();
                if(mp.pressed){
                    mp.run();
                }
            }

            // Check for click mouse events
            Iterator actions2 = MouseMap.map.entrySet().iterator();
            while(actions2.hasNext()){
                Map.Entry ap = (Map.Entry)actions2.next();
                Mapping mp = (Mapping)ap.getValue();
                if(mp.pressed){
                    mp.run();
                }
            }

            for(GameObject go : gameObjects){
                if(!go.getLeaveScreen()){
                    int goWidth = go.getWidth();
                    int goHeight = go.getHeight();
                    int goX = go.getX();
                    int goY = go.getY();
                    int gameWidth = Game.width;
                    int gameHeight = Game.height;
                    if(goX + goWidth >= gameWidth){
                        go.setX(gameWidth - goWidth);
                    }
                    if(goX <= 0){
                        go.setX(0);
                    }
                    if(goY + goHeight >= gameHeight){
                        go.setY(gameHeight - goHeight);
                    }
                    if(goY <= 0){
                        go.setY(0);
                    }
                }
            }
            this.repaint();
            Thread.sleep(roomSpeed);
        }
    }catch(Exception e){
    }
}

public void paintComponent(Graphics g){
    try{
        g.drawImage(bg, 0, 0, this);
        for(int i = 0; i < gameObjects.size(); i++){
            GameObject go = gameObjects.get(i);
            g.drawImage(go.getSprite(), go.getX(), go.getY(), this);
        }
    }catch(Exception e){
    }
}