Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does synchronized (this) lock only the synchronized block or all the "this" code?

public class ObjectCounter {
    private static long numOfInstances = 0;
    public ObjectCounter(){
        synchronized(this){
        numOfInstances++;
        }
    }
    **public static synchronized long getCount(){
        return numOfInstances;
    }**
//vs//
    **public static long getCount(){
        return numOfInstances;
    }**
}

if I'll run few threads, some of them call the static function getCount() and some of them create new instances. I want to get in each call to getCount() the real number of instances at the time.

  1. Is there a difference between the two options in the code?
  2. If I lock "this" shouldn't it mean that I can't call getCount() until the constructor exits the synchronized block (lets say if I don't write synchronize on the getCount()).
  3. if I do a synchronized block in some place in the code, does it lock only the synchronized block or all the "this" code?
  4. From here down EDIT: thank you all, it was very helpful, but I have a few more questions following your answers.
  5. If I understand correctly, the synchronized(this) block doesn't effect (or connected to) the static synchronized function (in lock terms not the numOfInstances increment)?
  6. is there a better option to make the increment and the getCount() function Thread-safe? (like open a static object and do synchronized(obj) instead synchronized(this) - friend suggested).
  7. If I had a f1() method (non-static) in ObjectCounter class, while one thread is in the synchronized(this) can other thread enter f1() block (not a synchronized class or have synchronized block inside)?
  8. If I had a f1() method (non-static) and f2() method (non-static) in ObjectCounter, in f1() I have synchronized(this) block. while one thread is in the synchronized(this) block, can other thread enter f1() block (not a synchronized class or have synchronized block inside)? (lets say both of the threads "working" on the same instance)

`

like image 571
Oriel Cochavi Avatar asked Jul 10 '15 13:07

Oriel Cochavi


People also ask

Does synchronized method lock whole object?

All synchronized blocks synchronize on the same object can only have one thread executing inside them at a time. All other threads attempting to enter the synchronized block are blocked until the thread inside the synchronized block exits the block.

What does synchronized lock do?

Object level lock vs class level lock – Important notes. Synchronization in Java guarantees that no two threads can execute a synchronized method, which requires same lock, simultaneously or concurrently. synchronized keyword can be used only with methods and code blocks.

What is true about lock in synchronized block?

Locks In Synchronized MethodsWhen a thread invokes a synchronized method, it automatically acquires the intrinsic lock for that method's object and releases it when the method returns. The lock release occurs even if the return was caused by an uncaught exception.

Do synchronized methods synchronize on the object or the class?

Synchronized static methods are synchronized on the class object of the class the synchronized static method belongs to. Since only one class object exists in the Java VM per class, only one thread can execute inside a static synchronized method in the same class.

What is the difference between method with synchronized keyword and block?

A method with synchronized keyword allows only one thread at a time to let its task complete. A thread that comes first would take the lock and perform its time, meanwhile other thread would wait for first thread to complete its task. A Block with synchronized keyword allows only one thread at a time to let its task complete.

What is a synchronized block in Java?

In Java, a Synchronized block helps in performing synchronization on any particular resource of the function or method. If there are 100 lines of code (LOC) and synchronization has to be done for only 10 lines, then a synchronized block can be used. Synchronized can be used as keyword, method and blocks.

What is the synchronized keyword in Java?

And to make it easier for programmers, Java provides the synchronized keyword that operates on the default lock of a class. This default lock is called intrinsic lock which belongs to every Java object. The synchronized keyword can be used at method level or code block level. Let’s look at the first approach first. 1. Synchronized Methods

How do I lock a map in a synchronized block?

For synchronized blocks, you can use any non-null object as a lock: synchronized (mymap) { mymap.put(..., ...); } For synchronized methods, the lock will be held throughout the method scope, while in the synchronized block, the lock is held only during that block scope (otherwise known as critical section).


1 Answers

Using synchronized means in order for a thread to execute that block or method, it has to acquire a lock referenced (explicitly or implicitly) by that block or method. For the static synchronized methods, that lock is the monitor on the class object. For the synchronized(this) block, the lock used is the monitor on the current instance. Sharing of locks between multiple methods or blocks is what enforces atomicity and memory visibility of updates, also the shared lock provides a shared communication path through which waiting and notification can take place.

Since the static synchronized blocks use a different lock from that used by the block in the constructor, entering a static synchronized block is not blocked by another thread's accessing the block that requires acquiring the lock on the current instance, and the synchronized block in the constructor has no effect on anything, the lock acquisition will always be uncontended. More importantly here, changes made by one thread in the constructor may not get seen by other threads using the getter. Synchronization affects both locking and memory visibility.

This changed version would work:

public class ObjectCounter {
    private static long numOfInstances = 0;
    public ObjectCounter(){
        synchronized(ObjectCounter.class){
            numOfInstances++;
        }
    }
    public static synchronized long getCount(){
        return numOfInstances;
    }
}

because the getter and the incrementing block are using the same lock. Making the different threads acquire the same monitor ensures that the change to the counter gets safely published so that another thread accessing the getter can see the updated value.

The synchronized keyword says, "you have to acquire a lock before you can enter", where for the method the lock is assumed: with the static keyword on the method it's the monitor on the class, without a static keyword it's the monitor on the current instance. For locking to work correctly the different blocks and methods need to use the same lock. There is arguably too much syntax sugar and too much making things convenient in how Java was designed: allowing implicit choice of locks and putting the monitor on java.lang.Object can cause confusion.

WRT your question #6: For what you're doing here you'd be better off with an AtomicLong. Use synchronized blocks for coordinating multiple changes that need to take place without interference from other threads.

Questions #3, #7 and #8 seem very similar: If a method/block isn't attempting to acquire a lock, nothing prevents threads from executing that method/block. The object as a whole doesn't get any protection, using the synchronized methods or blocks to enforce locking is what does the protecting. Think less in terms of "using the synchronized keyword" and more in terms of what lock threads need to acquire.

like image 94
Nathan Hughes Avatar answered Sep 19 '22 12:09

Nathan Hughes