ไม่ คอมโพเนนต์ Java Swing ไม่ใช่ Thread-Safe
ทำไม Swing ไม่ Thread-Safe?
- เพื่อ ลดความซับซ้อน ในการขยาย (extend) คอมโพเนนต์
- หลีกเลี่ยง Overhead ของ Lock และ State Restoration
- บางเมธอดรองรับ Multi-thread: repaint(), revalidate(), invalidate() ของ JComponent
Event Dispatch Thread (EDT)
คอมโพเนนต์ Swing เข้าถึงได้เฉพาะจาก EDT หลังจากพร้อมวาดบนหน้าจอ EDT คือเธรดที่เรียก callback เช่น paint(), update() และ Event Handler methods เมธอดที่ Thread-Safe เท่านั้นที่เรียกจากเธรดไหนก็ได้ แต่ส่วนใหญ่ไม่ Thread-Safe จึงต้องเรียกจาก EDT เท่านั้น
ตัวอย่าง: ใช้ SwingUtilities.invokeLater()
import javax.swing.*;
import java.awt.Dimension;
import java.awt.event.*;
public class EDTTest extends JPanel implements ActionListener {
private static EDTTest myPanel;
private static JFrame myFrame;
public EDTTest() { super(); }
public Dimension getPreferredSize() {
return new Dimension(500, 425);
}
public static void main(String[] args) {
// สำคัญ: ใช้ invokeLater ให้ GUI สร้างใน EDT
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI() {
myFrame = new JFrame("EDT Program");
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myFrame.setLocationRelativeTo(null);
myPanel = new EDTTest();
myFrame.add(myPanel);
initMenu();
myFrame.setVisible(true);
}
private static void initMenu() {
JMenuBar menuBar = new JMenuBar();
myFrame.setJMenuBar(menuBar);
JMenu file = new JMenu("File");
JMenuItem quit = new JMenuItem("Quit");
quit.addActionListener(myPanel);
file.add(quit);
menuBar.add(file);
}
public void actionPerformed(ActionEvent ae) {
if ("Quit".equals(ae.getActionCommand())) {
System.exit(0);
}
}
}
แนวทางปฏิบัติที่ดี (Best Practices)
- สร้าง/แก้ไข GUI ทุกอย่างใน EDT (ใช้ SwingUtilities.invokeLater() หรือ invokeAndWait())
- งานหนัก (DB, Network, Calculation) ทำใน Worker Thread (ใช้ SwingWorker)
- อัปเดต UI จาก Worker Thread ใช้ SwingUtilities.invokeLater()
- ไม่ควร sleep/wait ใน EDT (ทำให้ UI ค้าง)
ผลลัพธ์
หน้าต่าง JFrame แสดงเมนู File > Quit กด Quit จะปิดโปรแกรม ทั้งหมดทำงานใน EDT