一个Swing程序中一般有下面三种类型的线程:

* 初始化线程(Initial Thread)
* UI事件调度线程(EDT)
* 任务线程(Worker Thread)

每个程序必须有一个main方法,这是程序的入口。该方法运行在初始化或启动线程上。初始化线程读取程序参数并初始化一些对象。在许多Swing程序中,该线程主要目的是启动程序的图形用户界面(GUI)。一旦GUI启动后,对于大多数事件驱动的桌面程序来说,初始化线程的工作就结束了。

Swing程序只有一个用EDT,该线程负责GUI组件的绘制和更新,通过调用程序的事件处理器来响应用户交互。所有事件处理都是在EDT上进行的,程序同UI组件和其基本数据模型的交互只允许在EDT上进行,所有运行在EDT上的任务应该尽快完成,以便UI能及时响应用户输入。

Swing编程时应该注意以下三点:
1.从其他线程访问UI组件及其事件处理器会导致界面更新和绘制错误。
2.在EDT上执行耗时任务会使程序失去响应,这会使GUI事件阻塞在队列中得不到处理。
3.应使用独立的任务线程来执行耗时计算或输入输出密集型任务,比如同数据库通信、访问网站资源、读写大树据量的文件。

总之,任何干扰或延迟UI事件的处理只应该出现在独立任务线程中;在初始化线程或任务线程同Swing组件或其缺省数据模型进行的交互都是非线程安全性操作。

  • 事件分发线程:
    Swing中事件处理和绘画代码都在一个单独的线程中执行,这个线程就叫做事件分发线程。这就确保了事件处理器都能串行的执行,并且绘画过程不会被事件打断。
    在实际开发中存在事件分发线程中需要执行比较耗时的操作,导致此时调用并操作控件会导致例如文本框文本不显示等类似界面卡住的问题,只有在耗时操作全部完成后才恢复显示,原因是ui进程阻塞。

Swing 刷新组件java swing中两大原则: 1. 不要阻塞UI线程 2. 不要在UI线程外的线程去操作UI控件

1. 针对第一种原则:

使用线程提高性能
使用恰当的话,线程会是 一个很有用的工具。然而,当在一个Swing程序中使用线程时,你必须谨慎处理。虽然有危险,但线程还是很有用的。

将一个比较消耗时间的初始化任务移出主线程,可以使GUI出现得更快。耗时任务包括做额外的计算任务以及网络阻塞或硬盘I/O(比如,载入图片)。
将耗时任务移出事件分发线程,从而使GUI同时继续响应用户操作。
为了能重复执行一个操作,通常还需要在操作之间设置一个预置时间段(定时器)。
等待其他程序的消息。

2.针对第二种原则:

有时需要从事件派发线程以外的线程中更新Swing组件,例如,在actionPerformed中有很费时的操作,需要很长时间才能返回,按钮激活后需 要很长时间才能看到更新的列表,按钮会长时间保持按下的状态只到actionPerformed返回,一般说来耗时的操作不应该在事件处理方法中执行,因 为事件处理返回之前,其他事件是不能触发的,界面类似于卡住的状况,所以在独立的线程上执行比较耗时的操作可能更好,这会立即更新用户界面和释放事件派发 线程去派发其他的事件。

SwingUtilities类提供了两个方法:invokeLate和invoteAndWait,它们都使事件派发线程上的可运行对象排队。当可运行 对象排在事件派发队列的队首时,就调用其run方法。其效果是允许事件派发线程调用另一个线程中的任意一个代码块。

其本质还是只有从事件派发线程才能更新组件。

SwingUtilities.invokeLater(new Runnable() {

                public void run() {
                    要执行的代码
                }
            });

例子:

void Map_init() {
        int status;
        personal = new Personal();
        gettask = new Gettask();

        for (String tel : tel) {
            status = personal.post_personal(tel);
            /*SwingUtilities.invokeLater方法,在任何线程中调用invokeLater来请求事件分发线程(UI线程)以运行某段代码,避免阻塞
            该方法实际还是从事件分发线程*/
            SwingUtilities.invokeLater(new Runnable() {

                public void run() {
                    form_2.Area.append(tel + "\n");

                }
            });

//            status=gettask.post_gettask(tel);
            if (status == -1)
                continue;
            while (status == -2 || status == -3)
                status = (status == -2) ? personal.post_personal(tel) : gettask.post_gettask(tel);


        }
        this.tel_std = personal.tel_std;
        this.tel_strategy = personal.tel_strategy;
        this.tel_task = gettask.tel_task;


    }

区别

与invoikeLater一样,invokeAndWait也把可运行对象排入事件派发线程的队列中,invokeLater在把可运行的对象放入队列后就返回,而invokeAndWait一直等待知道已启动了可运行的run方法才返回。如果一个操作在另外一个操作执行之前必须从一个组件获得信息,则invokeAndWait方法是很有用的。
可以总结出它们的不同:可以从事件派发线程中调用invokeLater,却不能从事件派发线程中调用invokeAndWait,从事件派发线程调用invokeAndWait的问题是:invokeAndWait锁定调用它的线程,直到可运行对象从事件派发线程中派发出去并且该可运行的对象的run方法激活,如果从事件派发线程调用invoikeAndWait,则会发生死锁的状况,因为invokeAndWait正在等待事件派发,但是,由于是从事件派发线程中调用invokeAndWait,所以直到invokeAndWait返回后事件才能派发。