That's true, but misses the point of the question. Yes, an immutable class needs to be final, or have some other way to prevent extension, in order to be truly immutable. So make Immutable final. As for EffectivelyImmutable, obviously it's not required to obey all rules for being immutable - that's the point. Effectively immutable means it's not actually immutable, but it's being used in a way that its fields are never being changed after construction... so naively, we'd expect it to be immutable, and moreover, if we obey the rules of safe publication, it will be guaranteed to actually behave as if it were immutable.
The flip side is, if you have an effectively immutable object, and you don't obey the rule of safe publication, you may get unexpected behavior.
Here, I've taken Michael's original code and added a bit. I made both Immutable and EffectivelyImmutable final, and given them a shared interface with a getI() method to make them easier to compare. The only difference between the two is, Immutable has a final int field i, and EffectivelyImmutable has a non-final int field i. Then we create some instances and put them where other threads can find them and do something with them.
Now, this code is pretty silly. And I'm deliberately avoiding some more modern threading constructs like ExecutorService or an ArrayBlockingQueue because those take additional precautions to promote thread safety, and I'm deliberately trying to make an *unsafe* example. And I have a hard time analyzing all the rules for this, so I'm staying away from some more complex cases that I don't feel like trying to analyze.
We have two methods of publication here. The unsafe one adds an item to a LinkedList. The safe one does the same thing, except the LinkedList is wrapped with Collections.synchronizedList(). That means synchronization is used to access the data in the list, which is one of the ways to guarantee safe publication. Both lists are then polled from another thread, and getI() is called to observe the value of the field i. Which, we would expect, would be 42.
The point of this code is, when you use unsafe publication on an effectively immutable object, you may observe that the item.getI() code will return a 0, rather than the 42 that any sane person would expect here. Now in practice, you will almost certainly not see this. It's pretty unlikely. But it's possible, theoretically. If you run the code many, many times, you may have a higher chance of actually observing it. It may never happen, on your machine. But there are other machines out there that may exhibit this behavior.
Conversely, if we use safe publication on an EffectivelyImmutable instance, we are guaranteed to never see 0, only 42. And when we use an Immutable, whether published safely or unsafely, we are also guaranteed to see 42, never 0.
For most of us, using immutable instances is easier to understand. Using effectively immutable instances and making sure they're only published safely, that's harder to get right, more things can go wrong. But, it is one way of achieving thread safety in your programs.