代码之家  ›  专栏  ›  技术社区  ›  Logan Serman

EDT和主线程之间的通信

  •  0
  • Logan Serman  · 技术社区  · 17 年前

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

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

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

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

    显然,我必须在单独的线程中检查来自服务器的命令,并在EDT中运行GUI组件。我的第二个实现有两个类——一个用于GUI,另一个用于 玩家 . 当时的想法是 玩家 有一个保存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);
             }
        }
    

    这也不管用,因为 this 在新的 Runnable 对象引用 可运行的 对象,而不是 玩家 .

    我如何在 玩家 一个线程中的类和EDT线程中相应的GUI类?

    6 回复  |  直到 14 年前
        2
  •  3
  •   Laurent K    17 年前

    处理你的问题 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);
             }
        }
    }
    
        3
  •  2
  •   Tom Hawtin - tackline    17 年前

    boris pavlovi_135;获得正确的语法(实际上,您可以删除 this. 但是代码仍然没有意义。这个 gui 字段在 Runnable 事件已排队,因此播放机线程使用它是不安全的。

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

        4
  •  1
  •   Boris Pavlović    17 年前

    您可以尝试以下操作:

    班长 { 公共图形用户界面;

    ...
    
    // And then start this gui inside of the EDT.
    EventQueue.invokeLater(new Runnable()
    {
         public void run()
         {
              Player.this.gui = new GUI().setVisible(true);
         }
    }
    
        5
  •  1
  •   Pool    17 年前

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

    构造函数出现在edt上,但此类上调用的方法可能不是。

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

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

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

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

        6
  •  0
  •   oscarkuo    17 年前

    与其使用匿名内部类,不如声明一个实现可运行的类,并有一个以GUI实例为参数的构造函数?

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