0

我一直在问很多关于我最近一直在做的项目的问题。这是我所处的场景,任何帮助或指向正确方向都会有很大帮助......

这是一个由服务器和多个客户端构建的网络程序。每个客户端都有一个 GUI,它必须根据服务器发送的命令进行操作。每个客户端都包装在一个名为Player. 这Player有一个 GUI(扩展JFrame)和一个 main 方法,而服务器只有一个 main 方法(没有 GUI)。起初,这个类是在主线程中创建的,如下所示:

EventQueue.invokeLater(new Runnable()
{
    public void run()
    {
        new Player().setVisible(true);
    }
 });

这工作得很好,直到我意识到整个Player类现在都在 EDT 中执行。因此,当我等待来自服务器的命令时,整个 GUI 会锁定,直到发送该命令并执行适当的操作。可以想象,这是一个可怕的设计,并且被证明是编码环境的真正痛苦,因为每次您想要检查某些东西时,您必须找到一些疯狂的工作,以便 GUI 仍然保持完整。

显然,我必须在单独的线程中检查来自服务器的命令并在 EDT 中运行 GUI 组件。我的第二个实现有两个类——一个用于 GUI,一个用于Player. 这个想法是Player有一个保存 GUI 的变量,以便我可以从Player类中访问 GUI,如下所示:

class Player
{
    public GUI gui;

    ...

    // And then start this gui inside of the EDT.
    EventQueue.invokeLater(new Runnable()
    {
         public void run()
         {
              this.gui = new GUI().setVisible(true);
         }
    }

这也不起作用,因为thisRunnable对象内部指的是Runnable对象,而不是Player.

如何Player在一个线程中的类与 EDT 线程中相应的 GUI 类之间进行通信?

4

6 回答 6

3

要处理this指针问题,您应该编写:

class Player
{
    public GUI gui;

    ...

    // And then start this gui inside of the EDT.
    EventQueue.invokeLater(new Runnable()
    {
         public void run()
         {
              Playser.this.gui = new GUI().setVisible(true);
         }
    }
}
于 2009-04-16T07:45:46.187 回答
2

Boris Pavlović 获得了正确的语法(实际上您可以删除this.),但代码仍然没有意义。该gui字段在事件排队后的某个时间被初始化Runnable,因此播放器线程使用它是不安全的。

您可以Player在 EDT 上构建(但在 EDT 之外进行网络操作)。或者将 GUI 注册为Player. invokeAndWait会起作用,但很危险,因为它经常导致偶尔难以调试的死锁。

于 2009-04-16T08:30:13.367 回答
1
于 2009-04-16T04:40:17.880 回答
1

你可以试试这个:

类播放器 { 公共 GUI gui;

...

// And then start this gui inside of the EDT.
EventQueue.invokeLater(new Runnable()
{
     public void run()
     {
          Player.this.gui = new GUI().setVisible(true);
     }
}
于 2009-04-16T07:46:41.473 回答
1

“直到我意识到整个 Player 类现在都在 EDT 中执行”

构造函数发生在 EDT 上,但在此类上调用的方法可能不会。

您应该按照最初的意图构建播放器 GUI。

 EventQueue.invokeLater(new Runnable() 
 {
    public void run()
    {
        new Player().setVisible(true);
    }
 });

但是 Player 可以在构造函数中启动一个单独的线程(我个人会在 Player 之间共享一个连接)。

当然,来自服务器的回调方法在修改可见组件时应该使用 invokeLater()。

于 2009-04-16T11:22:50.213 回答
0

为什么不使用匿名内部类,而是声明一个实现 Runnable 的类并拥有一个以 GUI 实例作为参数的构造函数?

此外,如果您的 GUI 类不是线程安全的,请考虑使用消息队列在 EDT 和主线程之间进行通信。

于 2009-04-16T04:13:05.607 回答