2011-04-15 111 views
0

我正在使用Java中的应用程序来更新每秒的结果,直到它停止。在30秒钟内,它会每秒调用一组特定的方法,然后在接下来的30秒内调用另一组方法,然后再次调用第一组,然后依此类推。由于我希望能够在任何时候停止并重新启动在后台执行的计算,因此我创建了一个GUI和几个按钮来启动和停止新线程,以及一种显示结果的方法每一秒。Java线程问题

我遇到的问题是,一旦新线程启动,我不能切换回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; 
} 

} 
+0

请发表相关的代码。 – MByD 2011-04-15 21:44:00

+0

邮政编码。如果确实创建了一个新线程来执行该工作,它不应该影响GUI线程。 – 2011-04-15 21:44:15

+0

这篇文章将回答您的问题,并为您提供可帮助您的解决方案:[并发性](http://download.oracle.com/javase/tutorial/uiswing/concurrency/index.html) – 2011-04-15 21:46:24

回答

3

是的,你的GUI应该在它自己的线程中。

您尚未使用主题。您正在使用实现Runnable的自定义类。 Runnable!=线程。要做到这一点,而不是:

Thread thread = new Thread(new Threads()); 

当你想运行它,用

thread.start(); // not thread.run()!! 

请注意,我传递您的Runnable到一个真正的主题。我会建议将你的线程类重命名为更具体的东西。

所以,现在你已经设置了它的方式,你只是在与GUI相同的线程中运行Runnable。通过上面的代码,你将会产生一个新的执行线程。

+0

它应该模拟两条街道之间的交叉点。每秒钟的红绿灯,随机数的汽车等待绿灯。每秒钟的交通灯都是绿色的,一定数量的汽车离开了。我应该做的是监控每个交通灯的车辆数量。 – Skates 2011-04-15 21:48:09

+0

我不关心业务逻辑,我想看看你如何管理线程的实际代码。如果你的GUI在这个其他线程正在执行时被锁定,你要么没有正确地使用线程,要么另一个线程以某种方式阻止你的GUI(共享资源或者某个东西)。 – Brad 2011-04-15 21:49:54

+0

我已经发布了与我一直存在的问题相关的代码,请你看看吗? – Skates 2011-04-15 22:26:07

2

GUI在事件调度线程上更新。由于您的界面没有响应,EDT线程没有执行任何工作。这可能是因为:

  • 工作背景没有被在一个单独的线程中完成的,但实际上在美国东部时间
  • 你成功地创建一个新的后台线程,而不是让它异步运行,你是等待它完成。

您无法在另一个线程上运行GUI - 摆动必须在由系统创建的线程上运行 - 事件调度线程。

编辑:增加了更多的代码。您需要thread.start()而不是thread.run()。 start方法实际上会导致新线程开始执行(然后调用run()方法)。当您直接调用run()方法时,它只是一个常规方法调用,并在调用(GUI)线程上执行,因此UI被阻止。

+0

我相当确定这是第一个选项。我的线程是由GUI创建的,我假设这意味着它不会与GUI线程同时运行。我怎么能解决这个问题? – Skates 2011-04-15 21:52:05

2

是的,任何非gui活动(特别是长时间运行的任务)都应该在新线程上运行。

参见“EDT”,Swing的GUI线程的描述: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(),和其他人,让你开始...

1

Swing不是线程安全的。使用名为Event Dispatch Thread的东西进行摆动(请参阅mdma post以获得快速介绍),并且您可以找到一个很好的教程here。 Swing并不是要与线程一起运行,但可以使用Event Dispatch Thread的线程对几乎所有可以执行的任何事情进行建模,除了(大点)以外,它不会是并发的。

1

确切的解决方案取决于您必须做什么的确切细节以及是否需要更新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游戏的精彩书籍,强烈推荐。

EDIT1: 从代码中我发现你创建的线程很好,但是你应该使用线程的启动方法启动它,而不是运行。 --->为什么由@Brad解释。

祝你好运,博罗。