In general, you want to lock the "root" data object that you are managing. If, for example, you are going to subtract a value from a field in object A and add this value to object B, you need to block some object that is somehow common (at least by agreement) between A and B, perhaps the owner " object of two. This is due to the fact that you perform a lock to maintain a “contract” of consistency between the individual pieces of data - the locked object must be shared and conceptually cover the entire set of data that must be consistent.
The simple case, of course, is that you change field A and field B in the same object, in which case locking this object is an obvious choice.
A little less obvious when you are dealing with static data belonging to the same class. In this case, you usually want to lock the class.
A separate “monitor” object, created only for the lock function, is rarely required in Java, but can be applied to, say, elements of two parallel arrays, where you want to maintain consistency between element N two arrays. In this case, you may need something like a 3rd array of monitor objects.
(Note that this is just a “quick hack” when making some rules. There are many subtleties that you may encounter, especially when trying to allow maximum concurrent access to data with large access. Rarely beyond high-performance computing.)
No matter what you choose, it is important that the selection is consistent across all links to protected data. You do not want to lock object A in one case and object B in another when you are referencing / modifying the same data. (AND PLEASE do not fall into the trap of thinking that you can block an arbitrary instance of class A, and this will somehow help block another instance of class A. This is a classic beginner mistake.)
In the above example, you would usually want to lock the created object, considering that the consistency that you guarantee is an internal part of this object. But note that in this particular example, if the constructor for MyClass somehow does not allow the escape object to be addressed, there is no need to block at all, since there is no other way for another thread to get the address of the new object.