I'm not sure if I'm interpreting the javadoc right. When using a ReentrantLock after calling the lock method and successfully gaining a lock, can you just access any object without any synchronized blocks and the happend-before relationship is magically enforced?
I don't see any connection between the ReentrantLock and the objects I'm working on, that's why it is hard to believe I can work on them safely. But this is the case, or am I reading the javadoc wrong?
If thread A has modified some object inside a code block CB1 guarded by the lock and then releases the lock, and thread B enters in a code block guarded by the same lock, then thread B will see the modifications done by thread A in the code block CB1.
If two threads read and write the same shared state, then every read and write to this state should be guarded by the same lock.
It's ... a (mutex) lock:
void myMethod()
{
myLock.lock(); // block until condition holds
try
{
// Do stuff that only one thread at a time should do
}
finally
{
myLock.unlock()
}
}
Only one thread can hold the lock at a time, so anything between the lock() and unlock() calls is guaranteed to only be executed by one thread at a time.
The relevant Oracle tutorial can be found here.
There's no magic in it. You're safe if, and only if, all threads accessing an object use the same lock - be it a ReentrantLock or any other mutex, such as a synchronized block.
The existence ReentrantLock is justified by that it provides more flexibility than synchronized: you can, for example, just try to acquire the lock - not possible with synchronized.
Related
How does the java thread acquire a lock on a monitor used in synchronized block or monitor used in synchronized methods?
I read on multiple posts that in case of biased locking this information is stored in the object header using CAS operation and in case of contended situation wait set queue/ monitor queue is used but eventually lock marked in the object header only.
If this is the case then how is lock released? How object is marked free for acquiring a lock by another thread? are wait and notify methods used internally for this? If this is the case then why is making monitor null inside the synchronized block does not throw any exception.
The below example works perfectly fine, I was expecting NullPointerException assuming the end of the synchronized block will try to mark lock property to free the lock.
Example:
Object monitor = new Object();
synchronized (monitor){
System.out.println("before null");
monitor =null;
System.out.println("after null");
}
System.out.println("successfully Exited");
In case of biased locking: if the lock is biased towards a certain thread, no CAS is needed; just a volatile write. Biased lock information is kept in the mark word of the object header. Biased locking is going to be removed from JDK 15.
If a lock is contended, the object-monitor is used for synchronization. By default the object monitor is deflated, but if there is contention or you do a wait/notify, then the monitor gets inflated and is attached to the object.
On Linux blocking behavior is implemented using a wait-queue. So when a thread needs to wait for a lock, it is removed from the scheduler and added to the wait queue. When a lock unlocks, the thread on the wait queue is reinserted back into the scheduler.
The reason why the code doesn't throw an exception is that the monitor is read only once when the synchronized block is entered.
PS: It could be that your lock get completely removed due to lock elision. If the JIT can provide no other thread can acquire that lock, there is no point in synchronizing.
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?
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
the lock in a is acquired
code within the synchronized block is run (doSomething)
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.
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
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.
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.
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:
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.
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
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).
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.
From this link, I understand "Since the lock() and unlock() method calls are explicit, we can move them anywhere, establishing any lock scope, from a single line of code to a scope that spans multiple methods"
So what I understand from the above statement is
public class Test {
Lock l = new ReentrantLock();
void myMethod1() {
l.lock();
// Do my stuff here
}
void myMethod2() {
// Do more stuff here
l.unlock();
}
}
So basically 1 can call method1 and method2 in sequence and assume the call is thread safe.
I am not sure if it's true as said above.
What if somebody just calls method2 when i am already executing method1/method2 pair? Doesn't it complicate things.
I think a lock should be acquired and released in the function itself, before the control is returned from the function. Is my understanding correct?
Answer to first question:
What if somebody just calls method2 when i am already executing
method1/method2 pair? Doesn't it complicate things.
Suppose another thread calls the unlock() method on the ReentrantLock object then IllegalMonitorStateException would be thrown. Because the thread is not acquiring the lock and when it tries to unlock then it get exception.
It will not have any effect on execution or locking of first thread which is acquiring the lock.
Same thread:
Lock: If same thread which is acquiring the lock again tries to acquire the lock then lock counter increments.
Unlock: If same thread which is acquiring the lock tries to unlock then lock counter decrements and as soon as lock counter becomes 0, thread releases the lock.
Different thread:
Lock: If the lock is held by another thread then the current thread becomes disabled for thread scheduling purposes and lies dormant until the lock has been acquired, at which time the lock hold count is set to one.
Unlock: If different thread tries to unlock when it is NOT holding the lock then IllegalMonitorStateException is thrown.
That is the reason ReentrantLock lock and unlock mandates you to have try-catch or throw mechanism because it throws exception.
Read below excerpt from ReentrantLock#unlock()
If the current thread is the holder of this lock then the hold
count is decremented. If the hold count is now zero then the lock is
released. If the current thread is not the holder of this lock then
{#link IllegalMonitorStateException} is thrown.
Answer to second question:
I think a lock should be acquired and released in the function itself,
before the control is returned from the function. Is my understanding
correct?
That's the whole purpose of ReentrantLock, you can extend the locking mechanism to other methods, which you cannot do with synchronized blocks and methods. See below from ReentrantLock
A reentrant mutual exclusion Lock with the same basic behavior and
semantics as the implicit monitor lock accessed using synchronized
methods and statements, but with extended capabilities.
What if somebody just calls method2 when i am already executing method1/method2 pair? Doesn't it complicate things.
java.util.concurrent.locks.Lock is a more powerful mechanism than synchronized. Power tools are dangerous. Use them with caution.
See #hagrawal's answer for details.
Consider this example instead:
public class Test {
...
public void method1() {
l.lock();
...
}
public void method2() {
l.lock();
...
while (l.isHeldByCurrentThread()) {
l.unlock();
}
}
}
This setup means that once Thread A calls method1(), Thread B will block when calling any of the methods until Thread A calls method2(). So the lock scope spans zero or more invocations of method1() followed by a single invocation of method2().
Though in practice I would consider it far easier and cleaner to write code that restricts lock scope to a single method or part of a method.
My understanding of Java synchronized() blocks is that, if a thread already owns a lock on an object, it can enter a different block synchronized on the same object (re-entrant synchronization). Underneath, I believe that the JVM uses a reference count to increment/decrement the number of times a thread has acquired a lock, and that the lock is only released when the count is zero.
So my question is, if one encounters a piece of code that looks like this:
synchronized(this)
{
if (condition == WAITING)
{
synchronized(this)
{
condition = COMPLETE;
notify();
try
{
wait();
}
catch(InterruptedException e)
{
}
}
}
else
condition = READY;
}
what specifically happens when wait() is called? Does it merely decrement the count, or does it release the lock regardless of the count?
In the first case, it seems to me that it will produce a deadlock if lock re-entry had occurred, because it will still own the lock and would thus wait forever on another thread which is waiting on it.
In the second case, I can't really see what the point of the second synchronized block is at all.
The documentation for wait() says
"The current thread must own this object's monitor. The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object's monitor to wake up either through a call to the notify method or the notifyAll method. The thread then waits until it can re-obtain ownership of the monitor and resumes execution,"
so I think that the second case is the correct one, but I could be wrong. So am I missing something, or have I merely come across a redundant synchronized block that could just as easily be removed from the code?
There's nothing that necessitates the reacquiring of the lock after the if.
The wait() will also release the lock completely (otherwise it would be quite deadlock prone).
The only reason for the second synchronized that I can see, is that it previously used another object and someone modified it to use the same this by mistake.
I have this class:
public class MyClass {
public MyClass(){}
public void actionA(){
synchronized(MyClass.class){
System.out.print("A");
}
}
public void actionB(){
synchronized(MyClass.class){
actionA();
}
}
}
Which one (if any) is true?
Calling actionB() will lead to a deadlock, since actionA() can never aquire the lock associated with MyClass.class
Calling actionB() will not lead to a deadlock, since it already has aquired the lock associated with MyClass.class
#2 will happen, since the calling thread has the lock.
If however the code looked like this:
public void actionB(){
synchronized(MyClass.class) {
Thread thread = new Thread(new Runnable { run() { actionA(); }});
thread.start();
thread.join();
}
}
Then you would have a deadlock. locks are acquired on a per thread basis.
I find a useful mental picture is of a shared key for a padlock. Only one thread can have the key at a time, but obviously the same key will open any lock which it fits (the key fits any lock that uses the same sync object).
As an aside, it is bad practice to synchronize on any publicly visible field, since another piece of code far removed could feasibly lock on the same object leading to unnecessary contention and possibly deadlocks.
#2 will be happen.
Reentrant Synchronization
Recall that a thread cannot acquire a lock owned by another thread.
But a thread can acquire a lock that it already owns. Allowing a
thread to acquire the same lock more than once enables reentrant
synchronization. This describes a situation where synchronized code,
directly or indirectly, invokes a method that also contains
synchronized code, and both sets of code use the same lock. Without
reentrant synchronization, synchronized code would have to take many
additional precautions to avoid having a thread cause itself to block.