What should be used as a lock object of a synchronized statement in Java

Can anyone explain what is the difference between these examples?

Example # 1.

public class Main { private Object lock = new Object(); private MyClass myClass = new MyClass(); public void testMethod() { // TODO Auto-generated method stub synchronized (myClass) { // TODO: modify myClass variable } } } 

Example # 2.

 package com.test; public class Main { private MyClass myClass = new MyClass(); private Object lock = new Object(); public void testMethod() { // TODO Auto-generated method stub synchronized (lock) { // TODO: modify myClass variable } } } 

What should I use as a monitor lock if I need to take care of synchronization when a variable changes?

+4
source share
6 answers

Assuming Main not an “leaky abstraction,” here is the minimal difference between the first and second examples.

It is better to use an Object , rather than any other class, because the Object instance has no fields and therefore less. The idiom Object -as-lock makes it clear that the lock variable is only for use as a lock.

Having said that, there is a definite advantage in locking the object that will see nothing else. The problem with synchronizing the Main method to Main (e.g. this ) is that other unrelated code can also be synchronized with it for an unrelated purpose. By synchronizing on a dedicated (closed) lock object, you avoid this possibility.


In response to the comment:

In both cases there is a BASIC difference. In the first, you lock the object you want to manipulate. In the second, you block another object that has no obvious relation to the manipulated object. And the second case takes up more space, because you must allocate an (otherwise unused) object, and not use an existing instance that you are protecting.

I think that you are making the WRONG assumption - that MyClass is a data structure that needs protection. In fact, the question does not say this. Indeed, the way the example is written implies that locking is designed to protect the entire Main class ... not just part of its state. And in this context there is a clear connection ...

The only time it would be better to block MyClass would be if Main is an impenetrable abstraction that allowed another code to get a link to MyClass . This will be a poor design, especially in a multi-threaded application.

Based on the history of changes, I am sure that this is not the intention of the OP.

+2
source

Operator synchronization is useful when changing object variables.

You are changing myClass variables, so you want to lock the myClass object. If you need to change something in lock , then you want to lock the lock object.

In example # 2, you modify myClass , but lock object, which is nonsense.

+3
source

In the first case, you lock an object that is known only in this method, so it is unlikely that someone else will use the same object to lock, so such a lock is almost useless. The second option makes much more sense to me.

At the same time, the variable myClass is also known only in this method, so it is unlikely that another thread will gain access to it, so probably blocking is not needed here at all. A more complete example is needed to say more.

+2
source

The difference lies in the lock class and its volume - Both topics are pretty orthogonal with synchronization

  • objects with different classes can have different sizes

  • objects in different areas may be available in different contexts

In principle, both will behave the same with respect to synchronization

+1
source

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.

+1
source

Both examples are not good synchronization practices. lock Object should be placed in MyClass as a private field.

0
source

All Articles