Java中是否可以无限循环Thread和JFrame?

Is it possible to have infinite loop Thread and JFrame in Java?

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

但我面临一个无法解决的大问题,而且在互联网上也找不到任何答案。当我在 Thread 的无限循环中没有立即输出到控制台时,似乎 That Thread(在 Engine class 中)被 Program 杀死,只剩下 JFrame。但是当在无限循环中有一些输出到控制台时,线程(在引擎 class 中)完全按预期工作,这让我发疯:(

主要CLASS:

package ccarsimulator;

import javax.swing.SwingUtilities;

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

Window CLASS:

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);
    }
}

引擎CLASS:

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");
    }
}

在引擎的 class 线程无限循环中没有一些输出到控制台的结果是

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 Guru 朋友帮我解决了这一切。 并且还回答了我的问题,为什么在我发布这个问题后几秒钟内就有人不喜欢我仍然觉得不公平,因为我无法清楚地描述它,如果我这样做了,我会在不问的情况下找到我的问题的答案。

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

没有关键字 volatile 我的 Swing 线程正在更改 RAM 内存中的这两个引擎线程(bStopEnginebKeyPressed)变量,而这两个引擎线程的变量在CPU 缓存内存,因此引擎线程无法知道发生了什么变化,因为这两个变量没有在正确的位置发生变化。

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

只是告诉以后帮助其他人摆脱他们对类似问题的困惑,或者在我再次忘记这一切的时候帮助我自己;)