Documentation

The Java™ Tutorials
Hide TOC
Simple Background Tasks简单的后台任务
Trail: Creating a GUI With Swing
Lesson: Concurrency in Swing
Section: Worker Threads and SwingWorker

Simple Background Tasks简单后台任务

Let's start with a task that is very simple, but potentially time-consuming. 让我们从一个非常简单但可能耗时的任务开始。The TumbleItem applet loads a set of graphic files used in an animation. TumbleItem小程序加载动画中使用的一组图形文件。If the graphic files are loaded from an initial thread, there may be a delay before the GUI appears. 如果图形文件是从初始线程加载的,在GUI出现之前可能会有一段延迟。If the graphic files are loaded from the event dispatch thread, the GUI may be temporarily unresponsive.如果图形文件是从事件分派线程加载的,GUI可能暂时没有响应。

To avoid these problems, TumbleItem creates and executes an instance of SwingWorker from its initial threads. 为了避免这些问题,TumbleItem从其初始线程创建并执行SwingWorker的实例。The object's doInBackground method, executing in a worker thread, loads the images into an ImageIcon array, and returns a reference to it. 对象的doInBackground方法在工作线程中执行,将图像加载到ImageIcon数组中,并返回对它的引用。Then the done method, executing in the event dispatch thread, invokes get to retrieve this reference, which it assigns to an applet class field named imgs. 然后,在事件分派线程中执行的done方法调用get来检索此引用,它将此引用分配给名为imgs的小程序类字段。This allows TumbleItem to construct the GUI immediately, without waiting for the images to finish loading.这允许TumbleItem立即构建GUI,而无需等待图像完成加载。

Here is the code that defines and executes the SwingWorker object.下面是定义和执行SwingWorker对象的代码。

SwingWorker worker = new SwingWorker<ImageIcon[], Void>() {
    @Override
    public ImageIcon[] doInBackground() {
        final ImageIcon[] innerImgs = new ImageIcon[nimgs];
        for (int i = 0; i < nimgs; i++) {
            innerImgs[i] = loadImage(i+1);
        }
        return innerImgs;
    }

    @Override
    public void done() {
        //Remove the "Loading images" label.
        animator.removeAll();
        loopslot = -1;
        try {
            imgs = get();
        } catch (InterruptedException ignore) {}
        catch (java.util.concurrent.ExecutionException e) {
            String why = null;
            Throwable cause = e.getCause();
            if (cause != null) {
                why = cause.getMessage();
            } else {
                why = e.getMessage();
            }
            System.err.println("Error retrieving file: " + why);
        }
    }
};

All concrete subclasses of SwingWorker implement doInBackground; implementation of done is optional.SwingWorker的所有具体子类都实现doInBackgrounddone的实现是可选的。

Notice that SwingWorker is a generic class, with two type parameters. 请注意,SwingWorker是一个泛型类,有两个类型参数。The first type parameter specifies a return type for doInBackground, and also for the get method, which is invoked by other threads to retrieve the object returned by doInBackground. 第一个类型参数指定doInBackgroundget方法的返回类型,其他线程调用该方法来检索doInBackround返回的对象。SwingWorker's second type parameter specifies a type for interim results returned while the background task is still active. SwingWorker的第二个类型参数指定后台任务仍处于活动状态时返回的临时结果的类型。Since this example doesn't return interim results, Void is used as a placeholder.由于本例不返回临时结果,因此Void被用作占位符。

You may wonder if the code that sets imgs is unnecessarily complicated. 您可能会想,设置imgs的代码是否过于复杂。Why make doInBackground return an object and use done to retrieve it? 为什么让doInBackground返回一个对象并使用done来检索它?Why not just have doInBackground set imgs directly? 为什么不直接让doInBackground设置imgsThe problem is that the object imgs refers to is created in the worker thread and used in the event dispatch thread. 问题是imgs引用的对象是在工作线程中创建的,并在事件分派线程中使用。When objects are shared between threads in this way, you must make sure that changes made in one thread are visible to the other. 当以这种方式在线程之间共享对象时,必须确保在一个线程中所做的更改对另一个线程可见。Using get guarantees this, because using get creates a happens before relationship between the code that creates imgs and the code that uses it. 使用get可以保证这一点,因为使用get会在创建imgs的代码和使用imgs的程序之间创建一种先发生后发生的关系。For more on the happens before relationship, refer to Memory Consistency Errors in the Concurrency lesson.有关发生前关系的更多信息,请参阅并发课程中的内存一致性错误

There are actually two ways to retrieve the object returned by doInBackground.实际上有两种方法可以检索doInBackground返回的对象。

Be careful when invoking either overload of get from the event dispatch thread; until get returns, no GUI events are being processed, and the GUI is "frozen". 从事件分派线程调用get的重载时要小心;在get返回之前,不会处理任何GUI事件,GUI将“冻结”。Don't invoke get without arguments unless you are confident that the background task is complete or close to completion.除非您确信后台任务已完成或接近完成,否则不要在没有参数的情况下调用get

For more on the TumbleItem example, refer to How to Use Swing Timers in the lesson Using Other Swing Features.有关TumbleItem示例的更多信息,请参阅使用其他Swing功能课程中的如何使用Swing计时器


Previous page: Worker Threads and SwingWorker
Next page: Tasks that Have Interim Results