Invokeandwait Method in Swingutilities

invokeAndWait method in SwingUtilities

To understand what invokeAndWait() does, you first need to understand the event/thread model of Swing.

Basically, everything that affects the GUI in any way must happen on a single thread. This is because experience shows that a multi-threaded GUI is impossible to get right.

In Swing, this special GUI thread is called the Event Dispatch Thread, or EDT. It is started as soon as a Swing top-level component is displayed, and it's bascially a worker thread that has a FIFO queue of event objects that it executes one after another.

When a Swing GUI needs to be drawn or updated, the JRE places an event on the EDT queue. User actions that cause listeners to be called start as events on the EDT queue. And (this is this is the important part) everything your program does that changes the GUI (like registering listeners, adding/removing GUI components or changing model data that the GUI displays) must be placed in the EDT queue, or the GUI can get corrupted.

And now for the finish: invokeAndWait() places the Runnable you pass to it into the EDT event queue and waits until the EDT has executed it. This should be used when a non-GUI thread needs to do something that affects the GUI, but also needs to wait until it is actually done before it can continue. If you just want to do something that affects the GUI but do not care when it is finished, you should instead use invokeLater().

invokeAndWait Java

For code1 the 2 allocations and the add are executed on whatever thread calls init(). If this is not the event dispatch thread, then there may be a problem, as the Swing documentation says that almost all use of Swing should be done on the event dispatch thread.

For code2, the calls to Swing are guaranteed to be done on the event dispatch thread. This is the correct way to do things. It is ugly and complicated and you don't understand it (yet), but it is the right way to do things if init() will be called on any thread other than the EDT.

Java happens-before relationship invokeAndWait

The most difficult requirement here is:

The submitted Runnable is guaranteed to be executed exactly once.

Using a non-volatile (Plain) field for transfering the work task from the submitter to the executor would not create a happens-before relationship, but would also not guarantee that the executor sees the task at all or in a finite amount of time. The compiler would be able to optimize away assignments to that field, or during runtime the executor thread might only read the value from its cache instead of from main memory.

So for code using Java 8 or lower, I would say the answer is "No, such an invokeAndWait method is not possible" (except maybe using native code).

However, Java 9 added the memory mode Opaque. The page "Using JDK 9 Memory Order Modes" by Doug Lea, the author of JEP 193 (which added this functionality), describes this in great detail. Most importantly Opaque mode is weaker than volatile but provides still the following guarantee:

  • Progress. Writes are eventually visible.

    [...]

    For example in constructions in which the only modification of some variable x is for one thread to write in Opaque (or stronger) mode, X.setOpaque(this, 1), any other thread spinning in while(X.getOpaque(this)!=1){} will eventually terminate.

    [...]

    Note that this guarantee does NOT hold in Plain mode, in which spin loops may (and usually do) infinitely loop [...]

When designing such an invokeAndWait method without happens-before relationship you also have to consider that an action before starting a thread happens-before the first action in that thread (JLS §17.4.4). So the worker thread must be started before the action is constructed.

Additionally the "final field semantics" (JLS §17.15.1) have to be considered. When the caller of invokeAndWait creates the Runnable in the form of a lambda expression, then the capturing of variables by that lambda has (to my understanding) implicit final field semantics.

If so, please include an example implementation, which proves this.

Proving or disproving thread-safety or happens-before relationships using examples is difficult, if not impossible, due to being hardware and timing dependent. However, tools like jcstress can help with this.

Below is a (simplified) potential implementation for an invokeAndWait without happens-before relationship. Note that I am not completely familiar with the Java Memory Model so there might be errors in the code.

import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;

class OpaqueExecutor {
// For simplicity assume there will every only be a single work task
// So pending task being replaced by other task is not an issue
private final AtomicReference<Runnable> nextTask = new AtomicReference<>();

public OpaqueExecutor() {
Thread worker = new Thread(() -> {
while (true) {
// Use getOpaque() to no create happens-before relationship
Runnable task = nextTask.getOpaque();
if (task == null) {
// For efficiency indicate to the JVM that this is busy-waiting
Thread.onSpinWait();
} else {
// Clear pending task; memory mode here does not matter because we only want
// to guarantee that this thread does not see task again
nextTask.setPlain(null);
task.run();
}
}
}, "Worker thread");
worker.setDaemon(true);
worker.start();
}

public void invokeLater(Runnable runnable) {
// For simplicity assume that there is no existing pending task which could be
// replaced by this
// Use setOpaque(...) to not create happens-before relationship
nextTask.setOpaque(runnable);
}

private static class Task implements Runnable {
private final AtomicBoolean isFinished = new AtomicBoolean(false);
// Must NOT be final to prevent happens-before relationship from
// final field semantics
private Runnable runnable;

public Task(Runnable runnable) {
this.runnable = runnable;
}

public void run() {
try {
runnable.run();
} finally {
// Use setOpaque(...) to not create happens-before relationship
isFinished.setOpaque(true);
}
}

public void join() {
// Use getOpaque() to no create happens-before relationship
while (!isFinished.getOpaque()) {
// For efficiency indicate to the JVM that this is busy-waiting
Thread.onSpinWait();
}
}
}

public void invokeAndWait(Runnable runnable) {
Task task = new Task(runnable);
invokeLater(task);
task.join();
}

public static void main(String... args) {
// Create executor as first step to not create happens-before relationship
// for Thread.start()
OpaqueExecutor executor = new OpaqueExecutor();

final int expectedValue = 123;
final int expectedNewValue = 456;

class MyTask implements Runnable {
// Must NOT be final to prevent happens-before relationship from
// final field semantics
int value;

public MyTask(int value) {
this.value = value;
}

public void run() {
int valueL = value;
if (valueL == expectedValue) {
System.out.println("Found expected value");
} else {
System.out.println("Unexpected value: " + valueL);
}

value = expectedNewValue;
}
}

MyTask task = new MyTask(expectedValue);
executor.invokeAndWait(task);

int newValue = task.value;
if (newValue == expectedNewValue) {
System.out.println("Found expected new value");
} else {
System.out.println("Unexpected new value: " + newValue);
}
}
}

What should I do on exceptions thrown by SwingUtilities.invokeAndWait

InterruptedException is explained in this article.

The InvocationTargetException, it's thrown if the Runnables run method throws an exception.

Maybe running this example clarifies things:

        try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
System.out.println("1");
if (true) {
throw new RuntimeException("runtime exception");
}
System.out.println("2");
}
});
} catch (InterruptedException e) {
e.printStackTrace(System.out);
} catch (InvocationTargetException e) {
e.printStackTrace(System.out);
}

Return Value from InvokeAndWait

As nobody comes up with another solution, the best one that I could find out by myself is this: I create a simple object which contains the string to return. So I have a reference in both task contexts which I can use. I somebody has some comments to improve this solution, I'm open for it.

This is the class which holds the string.

public class StringCover {
private String string = "";

public String getString() {
return string;
}

public void setString(String string) {
this.string = string;
}

}

And this is the code from above with this solution.

public String getPath(String defaultPath)
{
StringCover stringCover = new StringCover();
try{
SwingUtilities.invokeAndWait( () -> {
// Ask here the user for the path
stringCover.setString(new PathSelector(defaultPath).getPath());
}
} catch (InvocationTargetException e) {
stringCover.setString("");
} catch (InterruptedException e) {
stringCover.setString("");
}
return stringCover.getString();
}

new Thread created when calling SwingUtilities.invokeAndWait()?

No,a new thread is not created when Runnable is used with SwingUtilities.invokeAndWait().
The Event Thread will end up calling the run() method of the Runnable when it's turn comes up on
the event queue.

Getting return values from SwingUtilities.InvokeLater calls?

It looks like your application data is all bound up inside your user interface objects. If everything you do can be done on the EDT, then you should be OK. You can make direct calls among the objects that need information from each other. Since all of this is on the EDT, it's effectively single-threaded, and there are no race conditions or deadlocks. This, however, can couple various parts of the UI code to each other rather too tightly. In that case you can use some kind of observer or listener pattern as the commenters have suggested. This works fine in a single-threaded, event-driven environment like with AWT/Swing.

But then you say you might want to do this from some thread other than the EDT. That changes everything.

(As an aside, this is the sort of thing that causes people to consider having all your application data bound up inside your UI objects to be an anti-pattern. It makes it quite difficult to get to this data from outside the UI subsystem.)

You could add an observer pattern, but there are restrictions. The UI owns the data, so only the EDT can change the data and fire events to observers. The observers lists need to maintained in a thread-safe fashion. Presumably the observers will want to update data structures in response to events. These data structures will have to be thread-safe, since they're accessed both from the EDT and from your other thread. This approach will work, but you have to do a lot of thinking about which thread is calling which methods, and which data structures have to be made thread-safe.

Assuming you don't want to go this route, let's return to your original question, which was about how to return something from invokeLater. Doing this would let you keep your data in the UI while allowing other threads to get data out of the UI when they need it. It is possible to do this, with a bit of indirection. It does have risks, though.

Here's the code. This can be called from the "other" (non-EDT) thread.

InfoObj getInfo() {
RunnableFuture<InfoObj> rf = new FutureTask<>(() -> getInfoObjOnEDT());
SwingUtilities.invokeLater(rf);
try {
return rf.get();
} catch (InterruptedException|ExecutionException ex) {
ex.printStackTrace(); // really, you can do better than this
}
}

The trick here is that RunnableFuture is an interface that is both a Runnable and a Future. This is useful because invokeLater takes only a Runnable, but Future can return a value. More specifically, Future can capture a value returned in one thread and store it until another thread wants to get it. FutureTask is a convenient, ready-made implementation of RunnableFuture that takes a Callable argument, a function that can return a value.

Basically we create a FutureTask and hand it a bit of code (the Callable, a lambda expression in this example) that will run on the EDT. This will gather the information we want and return it. We then post this to the EDT using invokeLater. When the other thread wants the data, it can call get() immediately or it can hang onto the Future and call get() later. There is a small inconvenience in that Future.get() throws a couple checked exceptions that you have to deal with.

How does this work? If the EDT runs the Callable first, the return value is stored in the Future until the other thread calls get() on it. If the other thread calls get() first, it's blocked until the value becomes available.

And there's the rub. Astute readers will recognize that this has the same risk as invokeAndWait(), namely, if you're not careful, you can deadlock the system. This can occur because the thread that calls get() might block waiting for the EDT to process the event posted by invokeLater. If the EDT is blocked for some reason -- perhaps waiting for something held by the other thread -- the result is deadlock. The way to avoid this is to be extremely careful when calling something that might block waiting for the EDT. A good general rule is not to hold any locks while calling one of these blocking methods.

For an example of how you can get yourself into trouble with invokeAndWait or with invokeLater(FutureTask), see this question and my answer to it.

If your other thread is entirely decoupled from the UI data structures, this technique should be quite effective.



Related Topics



Leave a reply



Submit