2015-11-25 33 views
1

我想用Swing编写一个多线程程序。从本质上讲,程序的工作原理是,当它运行时,它会有一个机器人(用截图中的一个圆圈表示),它在一个领域中四处探索。这个机器人应该由它自己的线程来控制。该程序有一个按钮“发射机器人”,将在现场创建另一个机器人(最多可以说10)。现在我有了该程序的基础知识,但它全部在一个线程下运行。我可以根据需要启动尽可能多的机器人,但它们都在单个线程下运行。但我希望当我点击“启动机器人”时创建一个独立的线程并控制该机器人。这是程序的外观如何,现在: enter image description hereSwing的多线程

该方案的UML图如下: enter image description here

自从长了一点,我不会张贴整个程序。但是,启动并更新机器人的方法(目前控制场上唯一一个机器人)如下:

public void gameStart(){ 
    Thread gameThread = new Thread(){ 
     public void run(){ 
      while(true){ 
       //execute one time step for the game 
       gameUpdate(); 

       //refresh screen 
       repaint(); 

       //give other threads time 
       try{ 
        Thread.sleep(1000/UPDATE_RATE); 
       }catch(InterruptedException e){ 
        e.printStackTrace(); 
       } 
      } 
     } 
    }; 

    gameThread.start(); 
} 

我的问题是如何实现多线程对这样的情景?我知道SwingWorker的基础知识,但由于我没有做过任何多线程,我不知道如何让多个线程工作并由一个线程更新(由线程控制的机器人的更新位置)。

编辑:只是为了说明我的观点,这是我正在研究的一个项目。这并不是说在这种情况下多线程是否有意义。

+0

我不会。对于你创建的每个新的'Robot',你都会创建一个新的'Thread',这不会很好地扩展。更好的解决方案是使用'gameUpdate'方法遍历'Robot'的'List'并遍历它们的更新逻辑,并且更新屏幕 – MadProgrammer

+0

@MadProgrammer I更新问题以反映这一事实这是我正在研究的一个项目。所以我需要按照我描述的方式来实现它。 – aaa

+0

接下来是一个问题,Swing是单线程的,如果机器人在Swing想要绘制时更新它的位置,则必须完成一个绘制点,那么就会冒着脏更新的风险。你的问题没有意义。如果你有一个'Thread'来控制每个'Robot',那么为什么你需要协调它们呢?让他们跑,做那件事。你真的有问题让他们渲染 – MadProgrammer

回答

2

创建一个RobotModel,其中包含一个Collection<Robot>并定义它们的交互。在SwingWorkerdoInBackground()执行中迭代该模型。当出现有意义的事件时调用publish(),并且process()通过查询模型更新到RobotWorld视图。正如here所讨论的那样,模型中不应该绘制图形,视图中也不应该有交互逻辑。一名工人应该适合一个适度复杂的模型,但你可以同步多个工人,如图所示here

1

达到此目的的一个好选择是使用ScheduledThreadPoolExecutor
通过实例化线程池:

ScheduledThreadPoolExecutor threadsPool = new ScheduledThreadPoolExecutor(size); 

要创建一个新的机器人主题,使用方法:

threadsPool.submit(new Runnable() { 
     @Override 
     public void run() { 
      launchRobot(); 
     } 
    }); 

这样,每个调用将实例化一个新的线程。
您可以通过“size”参数设置允许的Thread的总数限制。
你也可以传递一个结果每个线程完成使用后:

public <T> Future<T> submit(Runnable task, T result) 

如果你想少的细节,你可以让Java的做工作,为您提供以下便利API:
Executors.newCachedThreadPool()(无界线程池,自动螺纹回收)或:
Executors.newFixedThreadPool(int)(固定大小的线程池)

记住我们,遗嘱执行人。记得今天在这里做了什么。并且可能Adun看着你

+0

如何处理碰撞检测?如何在UI更新时防止可能的竞争条件? – MadProgrammer

+0

@ MadProgrammer UI更新应始终在EDT线程上调用,而不管线程的数量。 一个好方法是使用SwingWorkers或至少invokeLater()并通过应用程序关键区域进行同步 –

+0

当然,但是如何解决多线程和试图绘制其状态的UI之间的潜在竞争条件 – MadProgrammer

1

这个机器人应该由它自己的线程来控制。

为什么?

IMO,描述任何线程最重要的方式就是说它为什么等待。在互联网服务器中,接受线程等待来自新客户端的传入连接,并且客户端线程等待来自单个客户端的附加命令。在执行大规模并行计算的程序中,工作线程等待要执行的任务。在GUI程序中,事件调度线程等待键盘和鼠标事件。等等

您的机器人线程将等待什么?

如果等待时间过去(即,如果它调用了Thread.sleep()),那么你的GUI框架可能已经有一个计时器线程,做的是,你可能要考虑使用它。 (在Swing中,您将使用javax.swing.Timer类来提交新的定时任务。)