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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了是否有可能在Java中拥有无限循环的Thread和JFrame?相关的知识,希望对你有一定的参考价值。

我正在尝试创建一个小游戏,其中在一个线程中运行一个无限循环,它将执行引擎作业,而在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 Guru朋友帮我弄清了这一切。还回答了我的问题为什么在我发表这个问题的几秒钟之内就不喜欢我仍然觉得不公平,因为我无法清楚地描述它,如果我这样做,我会在不问的情况下找到我的问题的答案。

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

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

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

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

以上是关于是否有可能在Java中拥有无限循环的Thread和JFrame?的主要内容,如果未能解决你的问题,请参考以下文章

Java多线程和Thread.sleep [重复]

Python中可能有无限的for循环吗?

启动和停止无限循环

无限循环的线程是不是会导致 CPU 过多

std::thread 在无限循环中随机时间后锁定

EventQueue.isDispatchThread() 中的无限循环