14

In order to properly understand the issues and solutions for concurrency in Java, I was going through the official Java tutorial. In one of the pages they defined Intrinsic Locks and Synchronization link. In this page, they say that:

As long as a thread owns an intrinsic lock, no other thread can acquire the same lock. The other thread will block when it attempts to acquire the lock.

Also, they mention in the section Locks In Synchronized Methods that:

When 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.

For me this means that once I call a synchronized method from one of the threads, I will have hold of the intrinsic lock of the thread and since

Intrinsic locks play a role in both aspects of synchronization: enforcing exclusive access to an object's state and establishing happens-before relationships that are essential to visibility.

would another thread be unable to call another synchronized method of the same class? If yes, then the whole purpose of having synchronized methods is defeated. Isn't it?

Swapnil
  • 1,870
  • 2
  • 23
  • 48
  • Your question is ambiguous. What does "I" refer to when you ask, "Would *I* be unable to call another synchronized method..."? Frame your question in terms of threads. Are you asking if the same thread can call a synchronized method from a synchronized method? I.e., are Java intrinsic locks re-entrant? Or are you questioning the utility of a mutex? – erickson Jul 05 '16 at 22:07
  • Intrinsic method means that you don't have to create an object to synchronize your methods on. In comparison you can use an extrinsic lock by calling `synchronized(myLock) {...}`. This is an excerpt from the book Java concurrency in practice: "The fact that every object has a built-in lock is just a convenience so that you needn't explicitly create lock objects" – Alma Alma Jul 05 '16 at 22:21
  • I just updated the question so clear the ambiguity mentioned by the @erickson .. – Swapnil Jul 06 '16 at 06:21
  • If not mutual exclusion, what do you believe to be the purpose of synchronized methods? How do you believe that purpose is defeated by mutual exclusion? – erickson Jul 06 '16 at 06:39
  • I used to think that when a method is synchronized, there is a **lock exclusively** for that method and a thread cannot call the method when **this lock** is held by another thread. But a thread can call any other synchronized method of the same class. But I guess, I am more clear on this based on the answers below. Thanks! – Swapnil Jul 06 '16 at 06:43
  • @Swapnil please refer to my answer on the meaning of a synchronized method. – Adrian Shum Jul 06 '16 at 07:08

7 Answers7

16

Seems you have one misunderstanding (dunno if it caused the wrong conclusion) that no one has pointed out. Anyway, a brief answer:

Intrinsic Lock: Just think it as, every object in JVM has internally a lock. synchronized keywords tries to acquire the lock of the target object. Whenever you synchronized (a) { doSomething; }, what actually happens is

  1. the lock in a is acquired
  2. code within the synchronized block is run (doSomething)
  3. release the lock in a

and I wish you know

public synchronized void foo() {
  doSomething;
}

is conceptually the same as

public void foo() {
    synchronized(this) {
        doSomething;
    }
}

Ok, go back to your question, the biggest problem, imho, is :

For me this means that once I call a synchronized method from one of the threads, I will have hold of the intrinsic lock of the thread and since...

It is wrong. When you call a synchronized method, you are not get hold of the lock of the thread.

Instead, that thread will own the intrinsic lock of the object that is "owning" the method.

e.g. in thread1, you called a.foo(), and assume foo() is synchronized. thread1 is going to acquire the intrinsic lock of the object a referring.

Similarly, if AClass.bar() is called (and bar is synchronized and a static method), the intrinsic lock of AClass Class object will be acquired.

Adrian Shum
  • 38,812
  • 10
  • 83
  • 131
  • So, when I call a synchronized method from a **thread** and get the hold of the intrinsic lock of the **object**, will I be able to call an another synchronized method from another thread? Sorry for an earlier ambiguity in my question. – Swapnil Jul 06 '16 at 06:27
  • another thread that try to synchronize on THAT object (explicitly synchronized, calling a synchronize method of that object etc) will need to wait. You need to be clear on *what* synchronized method it is. If it is just a synchronized method of another unrelated object, of course it is ok – Adrian Shum Jul 06 '16 at 07:05
15

So just to repeat my comment above as an answer. Intrinsic locking means that you don't have to create an object to synchronize your methods on. In comparison you can use an extrinsic lock by calling synchronized(myLock) {...}.

This is an excerpt from the book Java Concurrency in Practice: "The fact that every object has a built-in lock is just a convenience so that you needn't explicitly create lock objects"

The book also says:

There is no inherent relationship between an object's intrinsic lock and its state; an object's fields need not be guarded by its intrinsic lock, though this is a perfectly valid locking convention that is used by many classes. Acquiring the lock associated with an object does not prevent other threads from accessing that objectthe only thing that acquiring a lock prevents any other thread from doing is acquiring that same lock. The fact that every object has a built-in lock is just a convenience so that you needn't explicitly create lock objects. [9] It is up to you to construct locking protocols or synchronization policies that let you access shared state safely, and to use them consistently throughout your program.

But in the footnote it says:

[9] In retrospect, this design decision was probably a bad one: not only can it be confusing, but it forces JVM implementors to make tradeoffs between object size and locking performance.

And to answer your last questions: you won't be able to call the synchronized methods from another thread, but you can keep entering from the same thread (intrinsic locks are re-entrant). So you have to imagine locking in this case as serializing method access from different caller threads.

If you use locking improperly and then you introduce liveness hazards, then yes it is defeated. That's why you have to make sure that your concurrent threads are not contending with each other too hard.

As Brian Goetz puts in this blog entry:

In tuning an application's use of synchronization, then, we should try hard to reduce the amount of actual contention, rather than simply try to avoid using synchronization at all

Giorgi Tsiklauri
  • 9,715
  • 8
  • 45
  • 66
Alma Alma
  • 1,641
  • 2
  • 16
  • 19
8

A lock can be held by only one thread at a time. That doesn't defeat the purpose; that is the purpose.

Threads mutually exclude each other from simultaneous action in critical sections by acquiring a lock, or mutex. This provides effective atomicity around a series of distinct actions, so that other threads never see intermediate states that might violate consistency guarantees.

erickson
  • 265,237
  • 58
  • 395
  • 493
3

Yes, you won't be able to call other synchronized method on the same object, because of the intrinsic lock. Which is at object level, only 1 thread will acquire it.

2

would I be unable to call another synchronized method of the same class? If yes, then the whole purpose of having synchronized methods is defeated. Isn't it?

No. You can't call other synchronized method on same object for Object level lock and you can't call other static sysnchronized method on same class.

But it does not defeat the purpose of having synchronisation.

If you follow the other documentation page on synchronized methods:

Making these methods synchronized has two effects:

  1. First, it is not possible for two invocations of synchronized methods on the same object to interleave. When one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object.
  2. Second, when a synchronized method exits, it automatically establishes a happens-before relationship with any subsequent invocation of a synchronized method for the same object. This guarantees that changes to the state of the object are visible to all threads.

If you allow two synchronized method to run in parallel. you will bound to get memory inconsistency errors on shared data.

On a different note, Lock provides better alternative synchronized construct.

Related SE question:

Synchronization vs Lock

Community
  • 1
  • 1
Ravindra babu
  • 37,698
  • 11
  • 250
  • 211
  • Thank you for the answer and the references. Though, your answer is good enough, the one by @Captain Fogetti has more detailed explanations with links to other useful resources. So, I mark that as correct. Thanks again. – Swapnil Jul 06 '16 at 06:37
1

It doesn't matter whether the synchronized method belongs to the same class or not, what matters is if the caller thread of the method acquires the lock or not, if it does, then it will be allowed enter the critical section because the lock is reentrant.

If it wasn't the case, then a recursive call would cause a deadlock,

fn(){
 synchronized(mutex){ // the current thread has already acquired the mutex
   fn();
 }
}

fn here wont deadlock because the lock is re-entrant, ie ( the thread that's already acquiring the lock can enter and renter the critical section again as long as it is still acquired).

Sleiman Jneidi
  • 22,907
  • 14
  • 56
  • 77
  • sry but I updated my question to be more clear. My question is about a different thread calling another `synchronized` method. – Swapnil Jul 06 '16 at 06:23
0

Locks can be divided in two classes - 'reentrant' and 'not reentrant'. In Java 'synchronized', base implementation of interface Lock (class ReentrantLock), interface ReadWriteLock (class ReentrantReadWriteLock) - are reentrant. Reentrancy means - one thread can again and again hold the lock.

Ivan Golovach
  • 199
  • 2
  • 5