本文是关于swing部分内容的最后一篇,之后开始讲解javafx,如果有使用java开发图形界面的需求,建议使用javafx技术。本文讲解一些关于swing的线程知识。

在Swing程序的开发中,需要建立3种线程的概念

  1. 初始化线程
    初始化线程用于创建各种容器,组件并显示他们,一旦创建并显示,初始化线程的任务就结束了。

  2. 事件调度线程
    通过事件监听的学习,我们了解到Swing是一个事件驱动的模型,所有和事件相关的操作都放是放在事件调度线程 (Event Dispatch Thread)中进行的。比如点击一个按钮,对应的ActionListener.actionPerformed方法中的代码,就是在事件调度线程中执行的。
    Swing里面的各种组件类都不是线程安全的,这就意味着,如果有多个线程,那么同一个JTextField的setText方法,可能会被多个线程同时调用,这会导致同步问题以及错误数据的发生。为了规避同步问题,以及降低整个Swing设计的复杂度,提高Swing的响应速度,Swing中的事件调度线程被设计成为了单线程模式,即只有一个线程在负责事件的响应工作
    在之前的文章中,我们把组件的初始化直接写在主线程中,初始化线程就是主线程。这时可能会有一些问题,可以查看官方文档上的示例。由于事件调度线程和初始化线程操作同一个组件,可能导致线程不安全的问题。为了规避这个问题的产生,创建和显示界面的工作,最好也交给事件调度线程。

public class TestThread1 {
    public static void main(String[] args) {
//        new TestFrame().setVisible(true);

      SwingUtilities.invokeLater(new Runnable() {
          public void run() {
              new TestFrame().setVisible(true);
          }
      });
    }

    static class TestFrame extends JFrame {
        public TestFrame() {
            setTitle("LoL");

            setSize(400, 300);

            setLocation(200, 200);

            setLayout(null);

            JButton b = new JButton("一键秒对方基地挂");

            b.setBounds(50, 50, 280, 30);

            add(b);

            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

            setVisible(true);

            System.out.println("当前线程是否是 事件调度线程: " + SwingUtilities.isEventDispatchThread());

        }
    }
}
  1. 长耗时任务线程
    有时候需要进行一些长时间的操作,比如访问数据库,文件复制,连接网络,统计文件总数等等。 这些操作就不适合放在事件调度线程中进行,因为占用时间久了,会让使用者感觉界面响应很卡顿。为了保持界面响应的流畅性,所有长耗时任务都应该放在专门的长耗时任务线程中进行。
    当SwingWorker执行execute的时候,调用默认有10根线程的线程池,执行doInBackground中的代码。
    下面是代码示例:
public class TestThread3 {
    public static void main(String[] args) {

        JFrame f = new JFrame("LoL");
        f.setSize(300, 300);
        f.setLocation(200, 200);
        f.setLayout(new FlowLayout());
        
        //任务执行完成后,按钮才可以继续点击
        JButton b1 = new JButton("在事件调度线程中执行长耗时任务");
        //任务没执行完也可以点击按钮
        JButton b2 = new JButton("使用SwingWorker执行长耗时任务");
        JLabel l = new JLabel("任务执行结果");
        f.add(b1);
        f.add(b2);
        f.add(l);

        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        b1.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                l.setText("开始执行完毕");
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }
                l.setText("任务执行完毕");
            }
        });
        b2.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {

                    @Override
                    protected Void doInBackground() throws Exception {
                        System.out.println("执行这个SwingWorder的线程是:" + Thread.currentThread().getName());
                        l.setText("开始执行完毕");
                        try {
                            Thread.sleep(5000);
                        } catch (InterruptedException e1) {
                            // TODO Auto-generated catch block
                            e1.printStackTrace();
                        }
                        l.setText("任务执行完毕");
                        return null;
                    }
                };
                worker.execute();

            }
        });

        f.setVisible(true);
    }
}

Q.E.D.


擅长前端的Java程序员