是否有可能在Java中拥有无限循环的Thread和JFrame?

问题描述 投票:-1回答:1

我正在尝试创建一个小游戏,其中在一个线程中运行一个无限循环,它将执行引擎作业,而在JFrame中将是所有在屏幕上输出的东西。

但我面临一个大问题,我无法修复,也没有在互联网上找到任何答案。当我在我的线程中的无限循环中没有立即输出到控制台时,似乎那个线程(在引擎类中)被程序杀死并且只留下了JFrame。但是当无限循环中有一些输出到控制台时,那么Thread(在Engine类中)完全正常工作,这让我疯狂:(

主要课程:

package ccarsimulator;

import javax.swing.SwingUtilities;

public class CCarSimulator {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            Window window = new Window("CCarsimulator");
        });
    }        
}

窗口类别:

package ccarsimulator;

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class Window extends JFrame{
    Engine oEngine = new Engine(this);


    JLabel LabelOutput = new JLabel();

    JPanel PanelCanvas = new JPanel();

    JLabel LabelSpeed;
    JLabel LabelRPM;
    JLabel LabelGearSet;
    JLabel LabelTotalTime;
    JLabel LabelFPS;
    JLabel LabelCPS;

    public Window(String WindowTitle){
        super(WindowTitle);

        this.addKeyListener(new KeyListener(){
            @Override
            public void keyTyped(KeyEvent e) {}
            @Override
            public void keyPressed(KeyEvent oKey) {
                System.out.println("Key Pressed");
                oEngine.bKeyPressed[oKey.getKeyCode()] = true;
            }
            @Override
            public void keyReleased(KeyEvent oKey) {
                oEngine.bKeyPressed[oKey.getKeyCode()] = false;
            }
        });
        this.addWindowListener(new WindowAdapter(){
            @Override
            public void windowClosing(WindowEvent oEvent){
                System.out.println("Closing a Window");
                oEngine.bStopEngine = true;
            }
        });

        this.add(PanelCanvas);
        PanelCanvas.add(LabelOutput);
        LabelOutput.setText("Test");

        this.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
        this.pack();
        this.setLocationRelativeTo(null);
        this.setVisible(true);
        this.setFocusable(true);
    }
}

发动机类别:

package ccarsimulator;

import java.awt.event.KeyEvent;

public class Engine extends Thread{
    Thread thisSelf = this;
    public boolean bStopEngine = false;
    public Window oWindow;

    public boolean []bKeyPressed = new boolean[KeyEvent.CHAR_UNDEFINED + 1];
    public boolean []bKeyReleased = new boolean[KeyEvent.CHAR_UNDEFINED + 1];

    public Engine(Window oWindow){
        this.oWindow = oWindow;
        thisSelf.start();
    }

    @Override
    public void run(){
        System.out.println("Waiting for window");
        //while(!oWindow.isVisible() && !bStopEngine);
        System.out.println("Engine is up and Running");
        while(!bStopEngine){
            //
            //---------------------------------------
            //Add some output to console to make this loop working...
            //---------------------------------------
            //
            if(bKeyPressed[KeyEvent.VK_ESCAPE]){
                System.out.println("Pressed Escape");
            }
        }
        System.out.println("Engine was disabled");
    }
}

在Engine的类中没有输出到控制台的结果线程无限循环是

Waiting for window
Engine is up and Running
Key Pressed
Key Pressed
Key Pressed
Key Pressed
Closing a Window

一些输出的结果是:

Waiting for window
Engine is up and Running
Some debug
Some debug
...
...
Some debug
Closing a Window
Some debug
Some debug
Engine was disabled
java multithreading loops jframe infinite
1个回答
1
投票

好吧,我的Java Guru朋友帮我弄清了这一切。还回答了我的问题为什么在我发表这个问题的几秒钟之内就不喜欢我仍然觉得不公平,因为我无法清楚地描述它,如果我这样做,我会在不问的情况下找到我的问题的答案。

问题是我必须在变量上添加volatile关键字,这些变量由两个线程(My Engine线程和Swing线程)处理。

没有关键字volatile我遇到了我的Swing线程正在改变RAM内存中的这两个引擎线程(bStopEnginebKeyPressed)变量,而这两个引擎线程的变量都在CPU Cache内存中,因此Engine线程无法知道某些更改因为这两个变量不是在正确的地方改变了。

还帮助我理解为什么我的代码只使用volatile设置这两个变量中的一个。这是因为Java应该默认将大约4KB的内存页面加载到CPU内存中。因此,如果幸运的话,我的volatile变量通过Swing Thread使用另一个使用的变量进入此页面而不使用volatile关键字,那么该页面仍然设置在线程同步上并且仍然将我的变量与Swing线程同步,这就是为什么它仍然有效。

只是告诉其他人将来摆脱他们与类似问题的混淆,或者为了将来再次忘记所有这一切,为自己摆脱困境;)

© www.soinside.com 2019 - 2024. All rights reserved.