I suggest using SwingWorker and using the publish method to publish updates to EDT. Then the EDT will apply one or more updates when the next one is planned. For example, suppose your result is calculating Integer instances:
// 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. } }
An alternative approach is to create a single Runnable instance that simply consumes Queue results every time it is scheduled. This is similar to how SwingWorker works under cover art, but gives you a little more control in that you can control the implementation of Queue and avoid constantly saving one of the empty SwingWorker threads.
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."); } }
source share