Re: Usefulness of "final" (Was: Re: Inserting In a List)
On 4/6/2013 4:31 AM, Robert Klemme wrote:
I think there's too much mixed here. "Thread safety" and
"(im)mutability" are two different concepts. They are orthogonal -
That's fair. I definitely over-sold the case between thread-safety in
general and immutability in that post you quoted. There's other ways of
achieving thread-safety than immutability. I was going fast and not
thinking thoroughly about what I typed.
But thread-safety and immutability are not orthogonal. Immutable
objects are all thread-safe. I urge you to re-read the section in JCIP
starting on page 46 that talks about immutability. Brain Goetz says
explicitly that immutability in Java requires final fields.
(He then makes an exception to that in a footnote, but I think we're all
quibbling too much over basic terms and understanding final fields to go
looking for sneaky ways around final fields.)
Later, after everybody's on the same page with respect to final fields,
we might talk about ways we don't need them. But I think we have to get
final field semantics down first or the discussion will be a mess.
First of all, objects which are mutable can be thread safe - it depends
on their implementation. (J?rg pointed that out already).
Yup, I missed that concept when I made my statement above. Mea culpa.
But: that does not necessarily constitute thread safety. An immutable
object can still be implemented in a thread unsafe manner. For example:
Well, there's safety and then there's other concepts related to
concurrency. I think it's best not to lump all concurrency related
discussion under the term "safety". What you showed was more a matter
of atomicity and mutex. So it might be better to use more specific
terms when describing it.
Here's another:
public final class OopsPrinter {
private final PrintStream out;
public KeyValuePairPrinter(PrintStream out) {
this.out = out;
}
/**
* Prints to a special PrintStream
*/
public void print(Object key, Object value) {
PrintStream save = System.out;
System.setOut( this.out );
System.out.printf( "blah blah etc." );
System.setOut( save );
}
}
I'd call this "global interference." Any thread calling this method
will set a global variable that affects all threads in the entire
system. It's safe because the JVM handles writes to System.out
specially so they are thread safe, but any other thread using System.out
at the same time as this method is executing will get a surprise. Brian
Goetz calls this "thread hostile."
("Interference" is a technical word used in a lot of literature on
concurrency, which I've run across before. It basically means a race
condition of some sort.)