It is possible that when the first thread gets to line 6, it could be preempted and the second thread promoted to the running state. The second thread could then reach line 6, and it too could be preempted. [The sleep() call is there specifically to force just such a sequence.] The first thread would be reinstated to the running state, and complete its updating of the balance attribute. Then when the second thread picks up where it last left off, it will overwrite the update that had just been made by the first thread. The output in lines 30 to 34 demonstrate that the "+20" update has been lost because the "-10" update has nullified its effect.
What is needed is a mechanism for making the updateBalance() method "thread safe". It needs to be treated "atomically" (cannot be swapped out of the running state until its entire body has finished executing). This is accomplished by assigning the modifier synchronized to the method's declaration (see the second line 3). The second block of output demonstrates the results when synchronized is added.
Even though the first thread is "sleeping" (line 6), the second thread is not allowed to call the "synchronized" updateBalance() method until the first thread releases its "lock" on the Account object. The first thread "wakes up" after ten milliseconds, completes its update, exits the "synchronized" method, releases its "lock" on the Account object; then, the second thread can call the "synchronized" method and do its thing.