You have to decide:
a) the mere use of final does not remove the need for synchronization
b) the mere use of final does remove the need for synchronization, and the
class that exposes the final instance of the list is still thread-safe.
I thought it was obvious, but of course you also have to prevent writes
to the object. final is necessary but not sufficient. Mea culpa if
that's the cause of the misunderstanding here. I should have been more
precise in my language. Unfortunately I was just focusing on one aspect
of making an object immutable, just the final-ctor combo, and ignoring
others.
But you can still have immutable, thread safe objects without final:
public class A {
private int i = 1;
public int getI(); { return i; }
}
This class is thread safe and immutable. And completely without final.
No, this is very explicitly wrong, and I'm sure the rest of the list
would agree. (I think you're confusing this with an example using a
static (class) field.)
The JLS explicitly says that writes on one thread are not visible
immediately to another thread. If thread A constructs this object, then
thread B calls getI, it's liable to see the previous value of i (0)
rather than the write by thread A which is still sitting in A's CPU cache.
You have to do something to flush that write out to main memory. In a
nutshell, that's what visibility means in the JLS. Two threads on two
CPUs won't see the same values unless force those writes to flush out to
main memory.
That memory barrier is the ctor. It alone is enough to make the writes
visible.
No, memory barriers are pretty expensive and the Java compiler doesn't
force them when not needed. Regular ol' POJO objects don't have a
memory barrier at the end of their ctor. That's the whole point of
section 17 in the JLS, Threads and Locks. It tells you how to use your
normally not-thread-safe objects safely.
I would like to see an example to back up this claim that it's poissible to
see a partially constructed object merely by it having non-final fields,
without giving out a reference to the partially constructed object (like I
did in my example).
There are several good examples in the JLS, which I'm going to refer you
too, so I don't louse-up an example again. There's example 17.4-1 in
the section on the Java memory model:
<
http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4>
There also another example 17.4.5-1 in the section on happens-before
consistency
<
http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4.5>
Both of those examples involve two writes, but that doesn't matter. The
accompanying text makes it clear that any write, even one single write,
can be re-ordered by the system.
Also take a look at section 17.4.1 where it talks about shared variables
and heap memory.
<docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4.1>
Instance fields are explicitly included, and your class A has an
instance field i that needs to be synchronized somehow. It's not thread
safe on its own.
Luckily someone else already quoted the point I'm trying to make that you
disagree with: you can have immutable objects without everything being
final just fine, as long as you don't let that lack of finality escape out
into the wild.
That example was really different than what you presented in your
example with the class A above. It's one reason why Arne's example from
JCIP also says "don't try this at home." ;-) It's really tough to
reason about these things and easy to get wrong; really really easy. I
urge you to study this because I'm concerned that you've missed a couple
of not-too-subtle points about concurrency in Java.