Reputation: 176
Java Concurrency in Practice describes several ways to ensure that an object is safely published, one of which is "assignment to a final field of a properly constructed object". My question is whether assignment to a final method argument is sufficient to ensure safe publication. Consider the following code:
private void collectResults() {
runOnBackgroundThread(new Runnable() {
public void run() {
displayResults(someBlockingMethodCall());
}
});
}
private void displayResults(final List<Foo> results) {
runOnUiThread(new Runnable() {
public void run() {
someUiMethodCall(results);
}
});
}
Each method queues a Runnable
for execution on another thread. someBlockingMethodCall()
is called on the background thread to perform some task, and someUiMethodCall()
is called on the UI thread to display the results.
If we assume that someBlockingMethodCall()
returns a mutable, unsynchronized list, such as an ArrayList, does assignment to the final argument of displayResults()
ensure that the list is safely published, or do I need to take extra steps to ensure safe publication?
Upvotes: 3
Views: 141
Reputation: 298469
There are several misconceptions here. The final
field publication guaranty is given to allow the programmer to assume correctly working immutable objects even if they are improperly published. This does not imply that you should design your software around improperly published objects.
Normally, the runOnUiThread
and runOnBackgroundThread
should post the Runnable
instances to the executing thread in a thread-safe way, hence, there is no need to rely on the final
field publication. Whether these two methods do it correctly, is impossible for us to tell as you didn’t post their code.
Further, the guaranty applies to, as you correctly cited, an “assignment to a final field of a properly constructed object” and local variables (which includes parameters) are not fields of any constructed object. But this isn’t something to worry about as parameters are, as any local variable, local to the thread executing the method, hence, not published at all.
There’s a corner case here as you are capturing the value of the local variable when creating an instance of the anonymous Runnable
implementation. This capturing has indeed the final
field assignment semantics, and that regardless of whether the parameter has been declared final
or is just effectively final.
But, as said, that shouldn’t drive your software design. You should ensure that runOnUiThread
and runOnBackgroundThread
do publish their runnables properly instead of thinking about final field publication. If these methods don’t publish the provided runnables properly, other problems may occur, but if they do, the publication of any object referenced by the runnables are properly published as well. This all assuming that you don’t modify the list after publication.
Upvotes: 1
Reputation: 40256
You are actually fine here. The only time you need to really worry about it if you write the results
to a shared variable that is not synchronized.
To hand it off to a thread there should usually be some synchronization in general. For instance, if you started a thread and the results
was passed to the Runnable, the start
of the thread is the sync point you'd need.
In this case, you are invoking runOnUiThread
, there is a synchronization point from the moment you submit the results
to the point where a thread picks it up.
So the submission here will be thread safe.
Upvotes: 3