I’m writing a client application with an accompanying GUI (Swing). My two classes, ClientClass and MainFrame, are running different threads yet need to call methods in one another. ClientClass instantiates the GUI (MainFrame) at some point during the applications life cycle on the EventQueue thread (displayGUI()). ClientClass contains many methods like recv(), called from the client classes thread, that updates MainFrame. In turn, MainFrame has methods that are triggered by events like the push of a button which call methods in ClientClass. I’m assuming the annoymous method that handles a button press in the example is being called by the EventQueue thread?
I’m pretty sure this kind of application is very common and I’d love the insight of others. I have a feeling that what I’m doing isn’t thread safe, so how can I fix/improve the current model of this application?
Example code:
MainFrame.java:
public MainFrame(ClientClass c) {
client = c;
// <Misc init code here>
btnSend = new JButton("Send");
btnSend.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent arg0) {
client.send("Hello!");
}
});
btnSend.setBounds(171, 120, 89, 23);
contentPane.add(btnSend);
}
public void updateElement() {
// Update of some element here, called from ClientClass
}
ClientClass.java:
private MainFrame mainFrame;
public ClientClass() {
}
public void displayGUI() {
final ClientClass c = this;
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
mainFrame = new MainFrame(c);
mainFrame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public void send(String msg) {
// Socket send operations here
// Currently called by the GUI's EventQueue thread?
}
public void recv() {
// Socket recv operations here
mainFrame.updateElement();
}
You can use
SwingUtilities
to invoke code on EDT (on UI thread).Mouse clicked is invoked on UI thread - so you should invoke
send
in the background (to not block UI if it takes long).On your
recv
method you should invokemainFrame.updateElement();
on UI thread if you change GUI state (JLabel text, etc.) - you do this by:Generally speaking - anything you do that may impact GUI elements (changing text, invalidating, adding components, etc.) you should do on EDT.
And everything that may block user interface you should do in background - spawning new
Thread
.If you need to block any events and wait to background - you can show modal
JDialog
(remember that you should hide it infinally
block - just in case)You should also look at the SwingWorker class and at the tutorial.