简体   繁体   English

EDT与主线程之间的通信

[英]Communication between the EDT and main threads

I have been asking a lot of questions about a project I have been working on recently. 关于我最近从事的一个项目,我一直问很多问题。 Here is the scenario I am in and any help or point in the right direction would help a lot... 这是我所处的场景,任何帮助或指出正确的方向都会有很大帮助...

This is a network program built with a server and multiple clients. 这是一个由服务器和多个客户端构建的网络程序。 Each client has a GUI which must act according to commands sent from the server. 每个客户端都有一个GUI,该GUI必须根据服务器发送的命令进行操作。 Each client is wrapped within a class called Player . 每个客户端都包装在一个名为Player的类中。 This Player has a GUI (extends JFrame ) and a main method, and the Server has a main method only (no GUI). Player具有GUI(扩展了JFrame )和main方法,而Server仅具有main方法(没有GUI)。 At first, this class was created in the main thread like this: 首先,此类是在主线程中创建的,如下所示:

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

This was working fine, until I realized that the entire Player class was now executing in the EDT. 一切正常,直到我意识到整个Player类现在都在EDT中执行。 So, when I wait for commands from the server the entire GUI locks up until that command is sent and proper actions are executed. 因此,当我等待来自服务器的命令时,整个GUI都会锁定,直到发送该命令并执行适当的操作为止。 As you can imagine, this is a horrible design and proved to be a real pain of a coding environment when every time you want to check for something you must find some crazy work around so that the GUI still remains intact. 可以想象,这是一个可怕的设计,并且在每次要检查某项内容时都必须进行一些疯狂的处理才能使GUI保持完整,这是编码环境的真正痛苦。

Obviously, I must check for the commands from the Server in a separate thread and run the GUI components in the EDT. 显然,我必须在单独的线程中检查来自服务器的命令,然后在EDT中运行GUI组件。 My second implementation had two classes - one for the GUI and one for the Player . 我的第二个实现有两个类:一个用于GUI,一个用于Player The idea was that the Player had a variable that held the GUI so that I could access the GUI from the Player class, something like this: 这个想法是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);
         }
    }

This doesn't work either, because this inside of the new Runnable object refers to the Runnable object, not the Player . 这也不行,因为this新的内部Runnable对象指Runnable对象,而不是Player

How can I communicate between the Player class in one thread and the corresponding GUI class in the EDT thread? 如何在一个线程中的Player类与EDT线程中的相应GUI类之间进行通信?

To handle your problem with the this pointer, you should write: 要使用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);
         }
    }
}

Boris Pavlović gets the syntax right (actually you could just remove the this. ), but still the code doesn't make sense. BorisPavlović正确使用了语法(实际上您可以删除this. ),但是代码仍然没有意义。 The gui field is initialised sometime after the Runnable event is queued, so it is unsafe for the player thread to use it. gui字段在Runnable事件排队后的某个时间初始化,因此播放器线程使用它是不安全的。

You could construct Player on the EDT (but do the network operations off EDT). 您可以在EDT上构造Player ,但可以在EDT上进行网络操作。 Or register the GUI as a listener (observer) of the Player . 或将GUI注册为Player的侦听器(观察者)。 invokeAndWait would work, but is dangerous as it often leads to the occasional difficult-to-debug deadlock. invokeAndWait可以工作,但是很危险,因为它经常导致偶尔难以调试的死锁。

You may try this: 您可以尝试以下方法:

class Player { public GUI gui; class Player {公共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);
     }
}

"until I realized that the entire Player class was now executing in the EDT" “直到我意识到整个Player类现在都在EDT中执行”

The constructor occurs on the EDT but methods called on this class might not be. 构造函数在EDT上发生,但在此类上调用的方法可能不是。

You should construct the player GUI as you originally intended. 您应该按照最初的意图构造播放器GUI。

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

But Player can launch a separate thread in the constructor (personally I'd share a connection between the Players). 但是Player可以在构造函数中启动一个单独的线程(我个人希望在Player之间共享一个连接)。

Of course, the callback methods from the server should use invokeLater() when modifying visible components. 当然,修改可见组件时,服务器的回调方法应使用invokeLater()。

Instead of using an anonymous inner class, why not just declare a class the implements Runnable and have a constructor that takes a GUI instance as argument? 与其使用匿名内部类,不如声明一个实现Runnable并具有以GUI实例作为参数的构造函数的类?

Also, if your GUI class is not thread safe, consider using a message queue to communicate between the EDT & main thread. 另外,如果您的GUI类不是线程安全的,请考虑使用消息队列在EDT和主线程之间进行通信。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM