我建议使用SwingWorker
并利用发布方法将更新发布回 EDT。然后,EDT 将在下次安排时应用一个或多个更新。例如,假设您的计算结果是Integer
实例:
// Boolean flag to determine whether background thread should continue to run.
AtomicBoolean running = new AtomicBoolean(true);
new SwingWorker<Void, Integer>() {
public Void doInBackground() {
while (running.get()) {
// Do calculation
Integer result = doCalculation();
publish(result);
}
}
protected void process(List<Integer> chunks) {
// Update UI on EDT with integer results.
}
}
另一种方法是创建一个实例,该实例在每次调度时Runnable
简单地从结果中消费。Queue
这类似于幕后SwingWorker
操作方式,但为您提供了更多控制权,因为您可以控制Queue
实现并避免永久持有SwingWorker
池线程之一。
private final Queue<Integer> resultQueue = Collections.synchronizedList(new LinkedList<Integer>());
// Thread-safe queue to hold results.
// Our re-usable Runnable to be run on the EDT. Consumes all results from the result queue
// before releasing the lock, although could obviously change this to consume up to N results.
Runnable consumer = new Runnable() {
public void run() {
synchronized(resultQueue) {
Integer result;
while ((result = resultQueue.take()) != null) {
// Update UI.
}
}
}
}
...
// Business logic to run on background thread. Conditionally schedules the EDT to run as required.
while (true) {
Integer result = doCalculation();
synchronized(resultQueue) {
boolean scheduleEdt = resultQueue.isEmpty();
// Queue was empty before this result is added so need to schedule the EDT to run again.
resultQueue.add(result);
}
if (scheduleEdt) {
SwingUtilities.invokeLater(consumer);
} else {
System.err.println("EDT already scheduled -> Avoiding unecessary reschedule.");
}
}