Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Java

Java Swing Thread-Safe หรือไม่?

ไม่ คอมโพเนนต์ 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