"In this example, the addName method needs to synchronize changes to lastName and nameCount, but also needs to avoid synchronizing invocations of other objects' methods. (Invoking other objects' methods from synchronized code can create problems that are described in the section on Liveness.) Without synchronized statements, there would have to be a separate, unsynchronized method for the sole purpose of invoking nameList.add."

I get the first part of that paragraph but I can't get my head around what it's saying in the section I've bolded and underlined? Is it trying to say that if

Code:

nameList.add(name)

was inside the synchronized block then that method itself wouldn't be able to be invoked by other methods until the object calling nameList.add(name) was finished? (this is alll based on the above code and if nameList.add(name) was contained within the synchronized block of code)

So for an example of how I'm interpreting this, if p called addName() then
p2 called add(), then p2 would be blocked from calling add() until the add() method invoked by p had finished execution?

I can see how that's confusing. The problem isn't with calling other objects' methods within your synchronized block or method; it's really just that you should do as little as you need to do within your block or method so that any objects in other threads can access those same resources quickly. In the example given in the tutorial, there may be multiple threads trying to add names simultaneously. To prevent them from colliding with each other, you synchronize the block so that only one thread can do it at a time. After that, you add it to a name list, which itself had better be synchronized to avoid the same kinds of conflicts. Note that this is an issue ONLY if you're using multiple threads; in a single-threaded application, it's impossible for this kind of simultaneous access.