A bit of help please, consider the bit of code below.
public class Widget {
public synchronized void doSomething() {
...
}
}
public class LoggingWidget extends Widget {
public synchronized void doSomething() {
System.out.println(toString() + ": calling doSomething");
super.doSomething();
}
}
I read that when doSomething() in LoggingWidget is called, the JVM will try to acquire a lock on LoggingWidget first and then on Widget.
I am curious to know the reason. Is it because the JVM knows that doSomething() has a call to super.doSomething() or because calling a subclass method will always acquire a lock on the superclass as well.
Cheers
You are mistaken - the locks are obtained at the instance level. There is only one lock in your example because there is only one instance created when you say:
Widget w = new LoggingWidget
You can view locks (also known as monitors, mutexes or semaphores) as being individually "attached" to every object instance in the JVM.
If you had another synchronized method on the LoggingWidget subclass, you would see this to be true. It would not be possible to call this (new) method and the doSomething method at the same time [with different threads on same object].
This also holds true for another synchronized method on the superclass (i.e. it is not affected in any way by methods being overridden).
public synchronized void doSomething() {
System.out.println(toString() + ": calling doSomething");
super.doSomething();
}
is the same as:
public void doSomething() {
synchronized (this) {
System.out.println(toString() + ": calling doSomething");
super.doSomething();
}
}
You're locking on the instance, not the class. So when super.doSomething() is called, you already have that instance locked.
There is only one instance to get the lock on, the instance of LoggingWidget, there is never an actual instance of Widget.
The lock is obtained when you call LoggingWidget.doSomething() and as you already have the lock when you call super.doSomething() that method is executed as normal.
Reentrancy works by first acquiring the lock. When one thread acquires the lock it is known in the jvm. When entering a block of code that is synchronized with the thread that is currently holding a lock, they are allowed to continue through without re acquiring the lock. The jvm then increases a counter every reentrant action, further decreasing when exiting that block until the count is zero. When the count is zero the lock is released.
B.Goetz - "JJava Concurrency in Practice" if intrinsic locks were not reentrant, the call to super.doSomething would never be able to acquire the lock because it would be considered already held, and the thread would permanently stall waiting for a lock it can never acquire. Reentrancy saves us from deadlock in situations like this.
Related
Are synchronized methods reentrant?
I have this code:
public class Main {
synchronized void m1() {
//some code
m2();
//some code
}
synchronized void m2(){
//some code
}
}
Say two threads (Thread A and Thread B) try to access m1() at the same time. Thread A takes lock first. After some time Thread A calls m2(), which is also synchronized on same object.
As I don't want to make any guesses can someone tell me this: Is there any guarantee what will happen when Thread A calls m2()? I mean once Thread A calls m2(), does it 'leave lock' at all? Because technically it left method's frame, so will it leave lock as well?
[EDIT]: Does Thread A get to run m2() every time once it calls it? Or does it leave lock so both Thread A and Thread B would race for their goals?
In Java locks are reentrant. If Thread A holds the lock, then it can start executing method m1. Eventually it will invoke method m2, since Thread A already holds the lock, it does not have to reacquire the lock again to execute method m2. Internally the lock keeps the owner field to track this. Even if the lock is already held, since the caller of m2 is the owner of the lock, the access is granted. This design strategy prevents deadlocks.
Can you tell me if following invocations are reentrant or not?
public class Foo {
public synchronized void doSomething() {}
public synchronized void doAnotherSomething() {}
}
public class Too {
private Foo foo;
public synchronized void doToo() {
foo.doSomething();
//...other thread interfere here....
foo.doAnotherSomething();
}
}
are 2 continuous invocations in method doToo() reentrant? I'm not sure about this case since foo.doSomething() method acquire and release the intrinsic lock, no nested synchronization between 2 invocations. Is there situation that other thread might interfere between 2 invocations?
First of all, regarding reentrant locks in Java:
Synchronized blocks in Java are reentrant. This means, that if a Java thread enters a
synchronized block of code, and thereby take the lock on the monitor object the block is synchronized on, the thread can enter other Java code blocks synchronized on the same monitor object.
Taken from here.
The two consecutive calls you described (in doToo) will not be interfered unless another object has a reference to Too's private Foo, since, to access foo, one needs to lock Too. However, the calls do not invoke reentry as the locks are acquired and released for every call. They would be reentrant if doSomething called doAnotherSomething or vice versa.
That depends entirely on what other threads are accessing. Can another thread take over the CPU between those functions? Yes. Will there be a race condition? Depends on many factors.
From what you posted foo.doSomething will be locked on foo, then released, then locked again upon entry to doAnotherSomething. So if another thread not locked on the same Too object tries to manipulate foo they will be able to do so between doSomething and doAnotherSomething. If everyone synchronized on the same Too object before manipulating the underlying foo object, then those two methods of foo will not have state manipulated between calls because the Too object method will block other threads until completion. Thus if you have a problem or not depends on your other accessors.
There is no reentrance here from what you posted, but java is ok with reentrant synchronization as Amir posted.
first of all locks are applicable on objects so need to create the object and then apply the lock.
are 2 continuous invocations in method doToo() reentrant? I
In your case they are not re-entrant . if code is something like below then they will be re-entrant .
public class Foo {
public synchronized void doSomething() {
doAnotherSomething();
}
public synchronized void doAnotherSomething() {}
}
Once lock has been acquired on one object then on same object it can traverse like in above case.
If I use synchronize(this) in two methods and one calls the other, will I get stuck in a deadlock situation or will it work because the thread already owns the lock?
Picture the class below:
public class Test {
public void foo() {
synchronize(this) {
bar();
}
}
public void bar() {
synchronize(this) {
// do something
}
}
}
As you can see, there are two methods foo and bar, which both rely on synchronization.
When calling foo(), a lock will be obtained on (this); will bar try to do the same when called by foo (and thus causing a deadlock) or will it realize that the lock has already been obtained by the same thread?
Hope my explanation is more or less clear ;-)
The synchronized block is reentrant (in fact, Java monitors are reentrant, to be perfectly clear), thus no deadlock can happen in your situation.
According to the docs:
Recall that a thread cannot acquire a lock owned by another thread.
But a thread can acquire a lock that it already owns.
If thread holds lock of object it can enter to other synchronized blocks based on that lock object.
Here you can read that
"...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."
One thing to be careful of though is if:
Thread A has the lock in foo() and needs to call bar()
and Thread B has the lock in bar() while needing to call foo()
If a synchronized method calls another synchronized method, is it thread safe?
void synchronized method1() {
method2()
}
void synchronized method2() {
}
Yes, when you mark methods as synchronized, then you are really doing this:
void method1() {
synchronized (this) {
method2()
}
}
void method2() {
synchronized (this) {
}
}
When the thread call gets into method2 from method1, then it will ensure that it holds the lock to this, which it already has, and thus it can pass through.
Now when another thread tries to get directly into method1 or method2, then it will block until it can get the lock (this), and only then it will enter into any of the two methods.
As noted by James Black in the comments, you do have to be aware with what you do inside of the method body.
private final List<T> data = new ArrayList<T>();
public synchronized void method1() {
for (T item : data) {
// ..
}
}
public void method3() {
data.clear();
}
Suddenly it's not thread safe because you are looking at a ConcurrentModificationException in your future because method3 is unsynchronized, and thus could be called by Thread A while Thread B is working in method1.
Is a method marked with synchronized call another synchronized method thread safe.
In general, it is not possible to say. It depends on what the methods do, and what other methods on the same and other classes do.
However, we can be sure that calls to method1 and method2 on the same object made by different threads will not execute simultaneously. Depending on what the methods do, this may be sufficient to say that the class is thread-safe with respect to these methods.
From the Java Tutorials site http://download.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html
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.
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
So Java will ensure that if 2 threads are executing the same method, the methods will not executed consurrently but one after another.
But you need to be aware of the Liveness problem, http://download.oracle.com/javase/tutorial/essential/concurrency/starvelive.html
And also whether you are locking uncessarily, cause in the code you used this, which locks the whole object, if your object only needs sync access to one variable you should just lock that variable.
Assume the following class
public class TestObject{
public void synchronized method1(){
//some 1000 lines of code
}
public void method2(){
//some 1000 lines of code
}
}
Let's assume there are two threads accessing the same instance of TestObject class, let's call them t1 and t2. I want to know what will happen in the following scenario.
When t1 is in midway of accessing method1(). Now t2 is trying to access method2().
When t1 is in midway of accessing method2(). Now t2 is trying to access method1().
My understanding is that for the first question, the thread t2 will not be given permission as the object will be locked by t1. For the second question, the thread t2 will be granted access and takes lock on the object and will stall t1 from execution. But my assumption was wrong. Can anyone explain this?
Thanks
Only the method with the keyword synchronized holds a lock for this object when a thread is running in that method.
Had both method 1 and method 2 been declared as synchronized, one thread would block the other even though they are trying to run different methods.
In your example only 1 method is blocking by an implicit lock.
As a result t1 and t2 can be running concurrently in method 1 and method 2 (or vice versa).
Only when trying to access method 1, a t1 or t2 would block if the lock has already been acquired
When you declare a method to be synchronized, e.g.:
public synchronized void foo() {
// Do something
}
the compiler treats it as though you had written this:
public void foo() {
synchronized (this) {
// Do something
}
}
In your example you have one synchronized method and one non-synchronized. This means that only access to method1 will be locked. Locking checks are only done on entry to a synchronized block, so calling method2 will not trigger any locking.
To answer your two questions, then, in both cases the two threads will be allowed to proceed because they are not trying to obtain a lock on the same object. If you declare method2 to be synchronized (or manually add a synchronized (this) block) then one thread will be forced to wait for the other.
Remember: synchronizing on an object does not prevent other threads calling methods on that object. It only prevents another thread entering a synchronized block with the same lock object.
Incidentally, it's often better to have an internal lock object rather than declaring methods to be synchronized, e.g.
class Foo {
private final Object LOCK = new Object();
public void doSomething() {
synchronized (LOCK) {
// Whatever
}
}
}
Otherwise I can break your thread-safety by doing this:
class MessEverythingUp {
public MessEverythingUp(Foo foo) {
synchronized (foo) {
while (true) {
System.out.println("Pwnd ur thread safety");
}
}
}
}
Since I'm locking the instance of foo, your synchronized methods (with their implicit "synchronized (this)") will not be able to obtain a lock and will block forever. Most importantly, you cannot prevent this because I can synchronize on whatever object I like. Obviously the example is extreme but you can get nasty, subtle deadlock bugs if you're not careful about this sort of thing.
In both cases, the second thread will be given permission to execute its method.
Since only one of these two methods contains the synchronized keyword, both of these methods can be executed simultaneously. The restriction is that only one method with that keyword can be executed at any given time, because executing that method requires a lock on the object. A thread without the keyword requires no lock and will always be allowed to execute regardless of the object being locked.
I also assume here that the 1000 lines of code in method2 does not contain a block like this:
synchronized (this) {
}
If it does, then the results will be different.
t2 will be allowed to start executing the method. When it hits the synchronized line, it will wait for t1 to finish method1 and release its lock before continuing.
t2 will be allowed to start executing the method so long as t1 is not within the synchronized code block. If it is, t2 will wait until t1 exits the block and releases the lock before beginning. If t1 has not yet entered the synchronized block, then t2 will acquire the lock, and t1 will wait as soon as it gets to the synchronized code block until t2 completes the method and releases the lock.
One method is synchronized while the other is not. So no matter whether the lock on an Object (in this is case the instance the method belongs to) has been acquired or not, the non-synchronized method will execute unimpeded (since it foes not try to acquire or wait for a lock). Which means in both cases both threads will run without waiting for each other - resulting in a possibly inconsistent state of the object.
method1() is synchronized and hence called as thread safe method. When multiple threads try to access this method simultaneously then only the lock on instance object will work.
method2() is not synchronized and hence is a thread unsafe method, other threads can call this method even if the some other thread has lock on the instance, that is why this method is called as thread unsafe method.
In both cases you mentioned one thread will get lock on the instance by calling method1() and other thread will try to access method2() which is unsafe and hence both thread will execute.
with regards
Tushar Joshi, Nagpur
Both threads will execute as if the lock does not exist.
The thread accessing method2 will never know that it should get a lock so it will execute even if an other thread holds the lock. Only synchronized methods will reserve the lock since synchronization is optional and not always wanted or even necessary.
If both threads execute method1 one of them will block until the other thread exits the method and releases the lock.
To make sure only one thread executes and all others wait you have to make both methods synchronized.