Thread safety is easier to understand when looking at bytecode. Even individual lines of code in a
Java function rarely correspond to a single bytecode instruction.
Pre-empting a thread can happen, at least in theory, between any two bytecode instructions -- even, in some cases, "during" one. It may be
unlikely that one thread interrupts another in such a way that it corrupts data, but it's
possible, and that's what you have to defend against.
To prove this, don't have one client fill the data and one get it -- have multiple clients send different strings of data, and get the value from another client "at the same time." Over enough trials, you'll see a value that's been messed up by failure to synchronize the action.
Instance variables, just to be persnickety, are neither threadsafe or threadunsafe. It's the methods that manipulate an instance variable without protecting it that makes it vulnerable to corruption.