Java EDT与主线程之间的通信
我最近一直在问很多关于一个项目的问题。这是我所处的场景,任何帮助或指向正确方向的点都会有很大帮助 这是一个由一个服务器和多个客户端构建的网络程序。每个客户端都有一个GUI,它必须根据服务器发送的命令进行操作。每个客户端都封装在一个名为Java EDT与主线程之间的通信,java,multithreading,swing,event-dispatch-thread,Java,Multithreading,Swing,Event Dispatch Thread,我最近一直在问很多关于一个项目的问题。这是我所处的场景,任何帮助或指向正确方向的点都会有很大帮助 这是一个由一个服务器和多个客户端构建的网络程序。每个客户端都有一个GUI,它必须根据服务器发送的命令进行操作。每个客户端都封装在一个名为Player的类中。这个Player有一个GUI(扩展JFrame)和一个main方法,而服务器只有一个main方法(没有GUI)。首先,该类是在主线程中创建的,如下所示: EventQueue.invokeLater(new Runnable() { pu
Player
的类中。这个Player
有一个GUI(扩展JFrame
)和一个main方法,而服务器只有一个main方法(没有GUI)。首先,该类是在主线程中创建的,如下所示:
EventQueue.invokeLater(new Runnable()
{
public void run()
{
new Player().setVisible(true);
}
});
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);
}
}
这很好,直到我意识到整个Player
类现在都在EDT中执行。因此,当我等待来自服务器的命令时,整个GUI将锁定,直到发送该命令并执行正确的操作为止。正如您可以想象的,这是一个可怕的设计,并被证明是一个真正的痛苦的编码环境,当您每次想要检查的东西,您必须找到一些疯狂的工作,使GUI仍然保持完整
显然,我必须在单独的线程中检查来自服务器的命令,并在EDT中运行GUI组件。我的第二个实现有两个类——一个用于GUI,另一个用于播放器。这个想法是Player
有一个保存GUI的变量,这样我就可以从Player
类访问GUI,如下所示:
EventQueue.invokeLater(new Runnable()
{
public void run()
{
new Player().setVisible(true);
}
});
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);
}
}
这也不起作用,因为新的Runnable
对象中的This
指的是Runnable
对象,而不是Player
如何在一个线程中的Player
类和EDT线程中相应的GUI类之间进行通信?与其使用匿名内部类,不如只声明一个实现可运行的类,并使用一个以GUI实例为参数的构造函数
此外,如果您的GUI类不是线程安全的,请考虑使用消息队列在EDT和主线程之间进行通信。
要处理此
指针的问题,您应该写:
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);
}
}
}
你可以试试这个:
职业选手
{
公共GUI
...
// And then start this gui inside of the EDT.
EventQueue.invokeLater(new Runnable()
{
public void run()
{
Player.this.gui = new GUI().setVisible(true);
}
}
Boris Pavlović获得了正确的语法(实际上您可以删除this.
),但代码仍然没有意义。gui
字段是在Runnable
事件排队后初始化的,因此播放器线程使用它是不安全的
您可以在EDT上构造Player
(但在EDT下执行网络操作)。或者将GUI注册为Player的侦听器(观察者)
invokeAndWait
可以工作,但危险的是,它经常会导致偶尔出现难以调试的死锁。“直到我意识到整个玩家类现在都在EDT中执行”
构造函数发生在EDT上,但在此类上调用的方法可能不存在
您应该按照最初的意图构建播放器GUI
EventQueue.invokeLater(new Runnable()
{
public void run()
{
new Player().setVisible(true);
}
});
但是玩家可以在构造器中启动一个单独的线程(就我个人而言,我会在玩家之间共享一个连接)
当然,在修改可见组件时,来自服务器的回调方法应该使用invokeLater()