Java线程问题

| 我正在开发Java应用程序,该应用程序需要每秒更新其结果,直到停止为止。在30秒内,它将每秒调用一组特定的方法,然后在接下来的30秒内调用另一组,然后再次调用第一组,依此类推。由于我希望能够随时停止和重新启动在后台执行的计算,因此,我制作了一个GUI和几个按钮来启动和停止新线程,以及显示该线程的方法。结果每秒。 我遇到的问题是,一旦启动新线程,我就无法切换回GUI,直到完成为止,并且由于线程会一直运行直到我告诉它停止,所以最终我无法能够退出无限循环。我可以通过将GUI放置在自己的线程中以使两个线程同时运行来解决此问题吗?如果是这样,我将如何从GUI内部进行操作? 我正在与多个班级合作,所以我不想发布无关紧要的内容。
public class GUI extends javax.swing.JFrame implements Runnable{
    Graphics g;
    Threads thread = new Threads();
    private void startButtonActionPerformed(java.awt.event.ActionEvent evt) {
         thread.run()
    }
    [..]
    private void stopButtonActionPerformed(java.awt.event.ActionEvent evt) {
         thread.stop()
    }
}
public class Threads implements Runnable{
boolean opened=false;
road first = new road();
public void run() {
    opened=true;
    first.standardInitialization();
    while(opened){
        for(int i=0; i<30 && opened; i++){
            try {
                first.redLightAction();
                System.out.println(\"cars: \" + first.firstLight.cars);
                Thread.sleep(1000);
            } catch (InterruptedException ex) {
                Logger.getLogger(Threads.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        for(int i=0; i<30 && opened; i++){
            try {
                first.greenLightAction();
                second.greenLightAction();
                System.out.println(\"cars: \" + first.firstLight.cars);
                Thread.sleep(1000);
            } catch (InterruptedException ex) {
                Logger.getLogger(Threads.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
}
public void stop(){
    opened=false;
}

}
    
已邀请:
是的,您的GUI应该在其自己的线程中。 您无法使用线程。您正在使用实现Runnable的自定义类。可运行!=线程。您想改为这样做:
Thread thread = new Thread(new Threads());
当您要运行它时,请使用
thread.start(); // not thread.run()!!
注意,我正在将您的Runnable传递给真实的线程。我建议将您的Threads类重命名为更具体的名称。 因此,现在设置的方式就是在与GUI相同的线程中运行Runnable。使用上面的代码,您将产生一个新的线程来执行。     
是的,任何非gui的活动(尤其是长时间运行的任务)都应在新线程上运行。 请参见Swing的GUI线程\“ EDT \”的说明:http://en.wikipedia.org/wiki/Event_dispatching_thread 您可以使用SwingUtilities的静态方法来促进EDT与其他线程之间的切换... http://download.oracle.com/javase/6/docs/api/javax/swing/SwingUtilities.html 请参阅invokeLater(Runnable),isEventDispatchThread()等,以使您入门...     
GUI在事件调度线程上更新。由于用户界面不响应,因此EDT线程未执行任何工作。这可能是因为: 后台工作不是在单独的线程上完成,而是在EDT上完成 您已经成功创建了一个新的后台线程,但是您正在等待它完成,而不是让它异步运行。 您不能在另一个线程上运行GUI-摆动必须在系统创建的线程-事件调度线程上运行。 编辑:添加了更多代码。您需要
thread.start()
而不是
thread.run()
。 start方法实际上是一个导致新线程开始执行的方法(然后调用run()方法)。当您直接调用run()方法时,它只是一个常规方法调用,并且在调用(GUI)线程上执行,因此UI被阻止。     
摆动不是线程安全的。使用名为Event Dispatch Thread的东西摇摆(请查看mdma帖子以获取快速介绍),您可以在此处找到一个不错的教程。 Swing并不是要与线程一起运行的,但是您可以使用事件分发线程(Event Dispatch Thread)对几乎所有可以使用线程进行的操作进行建模,除了(此处的重点),它不会是并发的。     
确切的解决方案取决于您要做的确切细节以及是否必须更新GUI。 根据我的阅读,我可以建议您实施某种游戏循环。据我了解,您可能想模拟流量并将其呈现给用户。然后,此类游戏循环将在每次迭代时首先进行所有计算并更新您的对象,最后在屏幕上显示新状态。这不是一个简单的任务,恐怕您应该熟悉Java中代码的并发和同步。
public void run()
{
    long startTime = System.currentTimeMillis();
    long currTime = startTime;
    isRunning = true;

    while(isRunning)
    {
        long elapsedTime = System.currentTimeMillis() - currTime;
        currTime += elapsedTime;
        update(elapsedTime);
        gameRender();
        paintScreen();
        try
        {
            Thread.sleep(1000);
        }catch(InterruptedException ex)
        {
            Logger.getLogger(GamePlayPanel.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
} 
您的类中将有一个类似于上述框架的框架,该框架实现Runnable,然后创建一个线程,将其作为您的类的参数,最后启动它。 可以在http://www.brackeen.com/上找到有关游戏构建的更多信息。该人极力推荐有关Java游戏的精彩著作。 编辑1: 从我观察到的代码中,您可以很好地创建Thread,但应使用未运行的Thread的start方法启动它。 --->为什么由@Brad解释。 祝你好运,博罗。     

要回复问题请先登录注册