# 简单的背景任务

> 原文： [https://docs.oracle.com/javase/tutorial/uiswing/concurrency/simple.html](https://docs.oracle.com/javase/tutorial/uiswing/concurrency/simple.html)

让我们从一个非常简单但可能耗时的任务开始。 [``TumbleItem`` ](../examples/components/TumbleItemProject/src/components/TumbleItem.java)小程序加载动画中使用的一组图形文件。如果从初始线程加载图形文件，则在 GUI 出现之前可能会有延迟。如果从事件调度线程加载图形文件，则 GUI 可能暂时无响应。

为了避免这些问题，`TumbleItem`从其初始线程创建并执行`SwingWorker`的实例。在工作线程中执行的对象的`doInBackground`方法将图像加载到`ImageIcon`数组中，并返回对它的引用。然后，在事件调度线程中执行的`done`方法调用`get`来检索此引用，该引用分配给名为`imgs`的 applet 类字段。这允许`TumbleItem`立即构建 GUI，而无需等待图像完成加载。

这是定义和执行`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);
        }
    }
};

```

`SwingWorker`的所有具体子类实现`doInBackground`; `done`的实现是可选的。

请注意，`SwingWorker`是一个泛型类，有两个类型参数。第一个类型参数指定`doInBackground`的返回类型，也指定`get`方法，由其他线程调用以检索`doInBackground`返回的对象。 `SwingWorker`的第二个类型参数指定后台任务仍处于活动状态时返回的中间结果的类型。由于此示例未返回中间结果，因此 [`Void`](https://docs.oracle.com/javase/8/docs/api/java/lang/Void.html) 用作占位符。

您可能想知道设置`imgs`的代码是否不必要地复杂化。为什么让`doInBackground`返回一个对象并使用`done`来检索它？为什么不直接设置`doInBackground` `imgs`？问题是对象`imgs`引用是在工作线程中创建的，并在事件派发线程中使用。以这种方式在线程之间共享对象时，必须确保在一个线程中进行的更改对另一个线程可见。使用`get`可以保证这一点，因为使用`get`会在创建`imgs`的代码与使用它的代码之间的关系之前创建 _。有关关系之前发生的更多信息，请参阅[并发](../../essential/concurrency/index.html)课程中的[内存一致性错误](../../essential/concurrency/memconsist.html)。_

实际上有两种方法可以检索`doInBackground`返回的对象。

*   不带参数调用 [`SwingWorker.get`。如果后台任务未完成，`get`会阻塞，直到它完成。](https://docs.oracle.com/javase/8/docs/api/javax/swing/SwingWorker.html#get--)
*   使用指示超时的参数调用 [`SwingWorker.get`。如果后台任务没有完成，`get`会一直阻塞，除非超时首先到期，在这种情况下`get`会抛出`java.util.concurrent.TimeoutException`。](https://docs.oracle.com/javase/8/docs/api/javax/swing/SwingWorker.html#get-long-java.util.concurrent.TimeUnit-)

从事件派发线程调用`get`的重载时要小心;直到`get`返回，没有处理任何 GUI 事件，并且 GUI 被“冻结”。除非您确信后台任务已完成或接近完成，否则不要在没有参数的情况下调用`get`。

有关`TumbleItem`示例的更多信息，请参阅[使用其他摆动功能](../misc/index.html)中的[如何使用摆动计时器](../misc/timer.html)。