Seems to me, either there's something synchronized in Integer.toString (which seems undesirable and therefore unlikely) or, statistically, in the rare cases that the writes don't take effect in time for the 'if' predicate, they do take effect a few nanoseconds later, in time for the conversions involved in the string construction. (Actually p.x is the only one at risk here, statistically speaking; the conversion of its value to a string will take plenty long enough for the write of p.y to take effect. Combine that with the fact that the write of p.x probably still precedes that of p.y, so that the one that's wrong in the 'if' statement is probably p.y, and you see that the odds of the wrong values being printed are vanishingly small.)
The exception is if you have tight control over your environment, have tests in place to verify that environment upgrades do not break your assumptions, and you desperately need to bend the rules, but even then, you should look really hard for better alternatives.
So "println() uses synchronized internally" means two println statements will never overlap each other, but still says nothing about their interaction with other objects, right? Does nothing to prevent switching threads in the middle of the println and getting two different values?
The bottom line is that the Point object should have been immutable, which would have made it safe for publication. That requires its fields to be final (among other things), which was not the case.