swing是单线程的,更新界面时需要在派发线程中更新,如不在会有错误。如果想要在非派发线程中更新UI需要调用SwingUtilities.invokeLater()。可我下面的程序注释掉了SwingUtilities.invokeLater(),程序运行的时候却没有报错,这是为什么?  不解 
下面程序模仿到数据库取数据,花费2秒,然后更新界面JTextArea import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class SwingTest extends JFrame {    private JLabel search = new JLabel("Search");    private JTextField tx = new JTextField(5);    private JButton btn = new JButton("Go");    private JTextArea ta = new JTextArea(5, 20);    private JPanel pUp = new JPanel();    public SwingTest() {
        Container con = getContentPane();
        con.setLayout(new BorderLayout());        pUp.setLayout(new FlowLayout(FlowLayout.LEFT));
        btn.setPreferredSize(new Dimension(52, 22));
        pUp.add(search);
        pUp.add(tx);
        pUp.add(btn);        addListener();        con.add(pUp, BorderLayout.NORTH);
        con.add(ta, BorderLayout.SOUTH);        pack();
        setVisible(true);    }    private void addListener() {        btn.addActionListener(new ActionListener() {            public void actionPerformed(ActionEvent e) {                new Thread() {
                    public void run() {
                        //SwingUtilities.invokeLater(new Thread() { //注释了程序运行却没有错误,不解
                            //public void run() {
                                new Thread(new GetDB(ta)).start();                            //}
                        //});                    }                }.start();            }        });    }    class GetDB implements Runnable {
        private JTextArea ta;        public GetDB(JTextArea ta) {
            this.ta = ta;
        }        public void run() {
            String s = null;
            try {
                Thread.sleep(2000); //模仿从数据库取数据,花费2秒;
                s = "test";
            } catch (Exception ee) {
                ee.printStackTrace();
            }            ta.append(s);
        }
    }    public static void main(String args[]) {
        SwingTest st = new SwingTest();
    }}

解决方案 »

  1.   

    JTextArea 类的append()方法的文档里专门说明这个方法是线程安全的
      

  2.   

    首先,2L的朋友说明了这个方法是线程安全的。
    其次,线程的错误不是说你想它出它就出的。线程的运行是不可控的,就算你调的是线程不安全的方法,代码也没考虑到线程安全,也不会每次运行都会出现。尤其是线程数量少的时候,很多隐藏的线程BUG是测试不出来的,等到上实际系统的时候,线程一多,就容易出现了。这就是为什么线程编程是难度很高的一种技巧。