The Java Tutorials have been written for JDK 8.Java教程是为JDK 8编写的。Examples and practices described in this page don't take advantage of improvements introduced in later releases and might use technology no longer available.本页中描述的示例和实践没有利用后续版本中引入的改进,并且可能使用不再可用的技术。See Java Language Changes for a summary of updated language features in Java SE 9 and subsequent releases.有关Java SE 9及其后续版本中更新的语言特性的摘要,请参阅Java语言更改。
See JDK Release Notes for information about new features, enhancements, and removed or deprecated options for all JDK releases.有关所有JDK版本的新功能、增强功能以及已删除或不推荐的选项的信息,请参阅JDK发行说明。
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
的所有具体子类都实现doInBackground
;done
的实现是可选的。
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
. doInBackground
和get
方法的返回类型,其他线程调用该方法来检索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
设置imgs
?The 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
返回的对象。
SwingWorker.get
with no arguments. SwingWorker.get
。get
blocks until it is.get
块,直到完成为止。SwingWorker.get
with arguments indicating a timeout. SwingWorker.get
。get
blocks until it is — unless the timeout expires first, in which case get
throws java.util.concurrent.TimeoutException
.get
块直到完成—除非超时首先到期,那样的话则get
会抛出java.util.concurrent.TimeoutException
。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计时器。