Java中的 SwingWorker
SwingWorker 是为Java编程语言的 Swing 库开发的一个抽象类。它用于在后台线程中执行冗长的 GUI 交互任务。在开发应用程序时,有时 GUI 在尝试执行一些庞大或冗长的任务时会挂起。这种滞后是一个很大的瓶颈。为此目的,开发了 SwingWorker,它在 GUI 仍然保持响应时安排在不同线程上执行这个冗长的任务。
Java语言有3个线程,分别列举如下:
- 当前线程(初始线程):这是执行初始应用程序逻辑的线程。
- 事件调度线程:所有事件处理代码都在这个线程上执行。
- 工作线程:也称为后台线程,执行所有耗时的后台任务。
SwingWorker 允许用户在 Worker Thread 上安排后台任务的执行。但是用户如何知道任务何时完成执行,或者用户是否需要根据线程执行更新 GUI(在初始线程上运行)?这意味着我们也需要线程间通信。 SwingWorker 专为在事件调度线程上提供通信的棘手情况而设计。
SwingWorker的重要方法
Method | Action Performed |
---|---|
cancel() | Attempts to cancel the execution of this task. This attempt will fail if the task has already been completed, has already been canceled, or could not be canceled for some other reason. If successful, and this task has not started when cancel is called, this task should never run. If the task has already started, then the mayInterruptIfRunning parameter determines whether the thread executing this task should be interrupted in an attempt to stop the task. After this method returns, subsequent calls to Future.isDone() will always return true. Subsequent calls to Future.isCancelled() will always return true if this method returned true. |
doInBackground() | Contains our logic of the background task i.e. what we want our thread to do. It runs on a worker thread and is necessary to implement. |
done() | It is called when the thread finished its execution. Also, any value returned by the doInBackground() function can be received inside this function using get(). Further, updates can be made to GUI inside this function. Thus, function executes on the Event Dispatch Thread after the doInBackground method is finished. |
execute() | Schedules this SwingWorker for execution on a worker thread. |
getProgress() | Returns the progress bound property. |
getState() | Returns the SwingWorker state-bound property. |
isCancelled() | Returns true if this task was canceled before it was completed normally. |
isDone() | Returns true if this task is completed. Completion may be due to normal termination, an exception, or cancellation — in all of these cases, this method will return true. |
get() | Waits if necessary for the computation to complete, and then retrieves its result. |
process() | Receives data chunks from the publish method asynchronously on the Event Dispatch Thread. Because this method is invoked asynchronously, publish() may have been called multiple times. |
publish() | It is to be used from inside the doInBackground method to deliver intermediate results for processing on the Event Dispatch Thread inside the process method. |
run() | Sets this Future to the result of computation unless it has been canceled. |
setProgress() | Sets the progress bound property. The value should be from 0 to 100. |
实现: SwingWorker
我们希望线程在单击按钮时开始执行。请参阅按钮的动作侦听器内的 startThread()。 startThread函数定义了一个javax.swing.SwingWorker类型的新 swingworker,其中:
- T——这个 SwingWorker 的 doInBackground 和 get 方法返回的结果类型,在下面的代码中为 String。
- V——这个SwingWorker的发布和处理方法用于执行中间结果的类型,在下面的代码中为Integer。
例子
Java
// Java Program to Illustrate Working of SwingWorker Class
// Importing required classes
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.List;
import java.util.concurrent.ExecutionException;
import javax.swing.*;
// Main class
// SwingWorkerSample
public class GFG {
private static JLabel statusLabel;
private static JFrame mainFrame;
// Method
public static void swingWorkerSample()
{
mainFrame = new JFrame("Swing Worker");
mainFrame.setSize(400, 400);
mainFrame.setLayout(new GridLayout(2, 1));
mainFrame.addWindowListener(new WindowAdapter() {
// Method
@Override
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
});
statusLabel
= new JLabel("Not Completed", JLabel.CENTER);
mainFrame.add(statusLabel);
JButton btn = new JButton("Start counter");
btn.setPreferredSize(new Dimension(5, 5));
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e)
{
System.out.println(
"Button clicked, thread started");
startThread();
}
});
mainFrame.add(btn);
mainFrame.setVisible(true);
}
// Method
private static void startThread()
{
SwingWorker sw1 = new SwingWorker() {
// Method
@Override
protected String doInBackground()
throws Exception
{
// Defining what thread will do here
for (int i = 10; i >= 0; i--) {
Thread.sleep(100);
System.out.println("Value in thread : "
+ i);
publish(i);
}
String res = "Finished Execution";
return res;
}
// Method
@Override protected void process(List chunks)
{
// define what the event dispatch thread
// will do with the intermediate results
// received while the thread is executing
int val = chunks.get(chunks.size() - 1);
statusLabel.setText(String.valueOf(val));
}
// Method
@Override protected void done()
{
// this method is called when the background
// thread finishes execution
try {
String statusMsg = get();
System.out.println(
"Inside done function");
statusLabel.setText(statusMsg);
}
catch (InterruptedException e) {
e.printStackTrace();
}
catch (ExecutionException e) {
e.printStackTrace();
}
}
};
// Executes the swingworker on worker thread
sw1.execute();
}
// Main driver method
public static void main(String[] args)
{
swingWorkerSample();
}
}
输出:
- 运行上面的代码,点击按钮,你会看到一个计数器递减。同时用 UI 做任何事情,它仍然是响应式的。
- 列表块是 process()函数的参数,包含线程发布的每个结果的列表,直到此时数据类型为 Integer。数据类型 Integer 应该与我们的 swingworker 声明相匹配。