Whatever is done to guarantee initialization safety must turn into a no-op with no performance cost on machines where it isn't needed. The synchronization and memory barriers don't cut it. There are tools that perform static and dynamic checks for data races. I have used some of them, and think these tools are an essential part of the development of any reliable, heavily multi-threaded program. It is unpleasant that constructors have a special magic power for synchronization that can't be obtained any other way.
Data races rot the brain and corrupt the soul.
Also, I suspect that guaranteeing full initialization safety will prove to have a substantial performance impact, more than is acceptable. If it isn't a problem on today's machines, but it becomes a serious problem on machines 5 years from now, we won't be able to change this decision because the installed code base will be huge and we will have trained a generation of Java programmers to use data races. I think that this won't be too expensive to discourage use of final, and then only on very few machines.