[英]Communication between the EDT and main threads
關於我最近從事的一個項目,我一直問很多問題。 這是我所處的場景,任何幫助或指出正確的方向都會有很大幫助...
這是一個由服務器和多個客戶端構建的網絡程序。 每個客戶端都有一個GUI,該GUI必須根據服務器發送的命令進行操作。 每個客戶端都包裝在一個名為Player
的類中。 該Player
具有GUI(擴展了JFrame
)和main方法,而Server僅具有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);
}
}
這也不行,因為this
新的內部Runnable
對象指Runnable
對象,而不是Player
。
如何在一個線程中的Player
類與EDT線程中的相應GUI類之間進行通信?
要使用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);
}
}
}
BorisPavlović正確使用了語法(實際上您可以刪除this.
),但是代碼仍然沒有意義。 gui
字段在Runnable
事件排隊后的某個時間初始化,因此播放器線程使用它是不安全的。
您可以在EDT上構造Player
,但可以在EDT上進行網絡操作。 或將GUI注冊為Player
的偵聽器(觀察者)。 invokeAndWait
可以工作,但是很危險,因為它經常導致偶爾難以調試的死鎖。
您可以嘗試以下方法:
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);
}
}
“直到我意識到整個Player類現在都在EDT中執行”
構造函數在EDT上發生,但在此類上調用的方法可能不是。
您應該按照最初的意圖構造播放器GUI。
EventQueue.invokeLater(new Runnable()
{
public void run()
{
new Player().setVisible(true);
}
});
但是Player可以在構造函數中啟動一個單獨的線程(我個人希望在Player之間共享一個連接)。
當然,修改可見組件時,服務器的回調方法應使用invokeLater()。
與其使用匿名內部類,不如聲明一個實現Runnable並具有以GUI實例作為參數的構造函數的類?
另外,如果您的GUI類不是線程安全的,請考慮使用消息隊列在EDT和主線程之間進行通信。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.