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.
Related
I'm newish to Java concurrency and I'm trying to better understand monitors.
Suppose I have one object, with a method that takes some kind of reference argument and uses that argument as a monitor in a synchronized block:
class Entity() {
public void myMethod(Object monitor) {
synchronized(monitor) {
// critical stuff
}
}
}
Can two threads enter that section at the same time on the same entity if they use different objects for the monitor?
final Entity myEntity = new Entity();
for (int i = 0; i < 3; i++) {
new Thread() {
public void run() {
// Can these all run concurrently?
myEntity.myMethod(new Object());
}
}.start();
}
If I understand monitors correctly, then yes, all the threads can enter the synchronized block at the same time, because each monitor acts as a totally different mutex and none of the threads are aware of the other threads in that block.
It's been difficult to find documentation on this because tutorials mostly seem to just use "this" as the monitor.
Can two threads enter that section at the same time on the same entity
if they use different objects for the monitor?
From the oracle tutorial one can read:
Every object has an intrinsic lock associated with it. By convention,
a thread that needs exclusive and consistent access to an object's
fields has to acquire the object's intrinsic lock before accessing
them, and then release the intrinsic lock when it's done with them. A
thread is said to own the intrinsic lock between the time it has
acquired the lock and released the lock. 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.
This informally means that one can synchronize using any Java Object. A block enclosed by a clause synchronized on a single object instance will be executed sequentially, i.e., executed by the thread holding the lock of the object being synchronized.
Can two threads enter that section at the same time on the same entity
if they use different objects for the monitor?
Yes, multiple threads can execute (in parallel) the same code region wrapped with a synchronized clause as long as each of those threads is synchronizing using different object instances.
One can also synchronize using the class itself, rather than its instances:
synchronized (SomeClass.class){
System.out.println("Hello World");
}
In such cases, all the threads that use the clause synchronized on the class SomeClass, will have to synchronize among each other.
One can also use clause synchronized on methods (e.g., public synchronized void method2()); for non-static methods the object being synchronized will be the object to which that method belongs, whereas for static methods (e.g., public static synchronized void method1()) will be class itself to which that method belongs.
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()
Consider following class that I have wrote for testing the locking of non-primitive variable (myObject). If all threads are working on same object instance of SynchronizationTest, my questions are:
I understand that if thread1 is executing set(...) method then any other thread (lets say thread2) is okay to execute either of the anotherSetWithSynchronized(...) or anotherSetWithoutSynchronized(...).
If thread1 has locked the object of SynchronizationTest while executing set(...), does it mean it has acquired lock on all member object variable ? like in this case myObject. If not then,
If thread1 is executing set(...) can thread2 execute anotherSetWithSynchronized(...) concurrently?
Are none of the two methods can execute simultaneously by thread?
Is this design wrong? Do I need to explicitly lock myObject in synchronized set(...) method. Like this:
public synchronized void set(MyValue myValue) {
synchronized (myObject) {
myObject.put(myValue);
}
}
Here's my code:
public class SynchronizationTest {
private MyObject myObject = new MyObject();
public synchronized void set(MyValue myValue) {
myObject.put(myValue);
}
public void anotherSetWithSynchronized(MyValue myValue) {
synchronized (myObject) {
myObject.put(myValue);
}
}
public void anotherSetWithoutSynchronized(MyValue myValue) {
myObject.put(myValue);
}
}
1: No, set(...) method is guarded by "SynchronizationTest" Object's lock.
2: Yes, their guard objects are different as you've designed.
3: One thread can only run one method per time. If you mean two threads, as I've explained, the methods are guarded by two objects and therefore they can be executed simultaneously
4: Yes, you're right.
The intrinsic lock in Java is described as follows in the book "Java Concurrency In Practice":
A synchronized block has two parts: a reference to an object that
will serve as the lock, and a block of code to be guarded by that
lock. A synchronized method is shorthand for a synchronized block
that spans an entire method body, and whose lock is the object on
which the method is being invoked. (Static synchronized methods use
the Class object for the lock.)
For more details, you can refer to section 2.3.1 of "Java concurrency in Practice".
synchronized method is equivalent to
public void method(){
synchronized(this){
//something
}
}
1) no
Synchronization is only on specified objects, not on its members.
2) no
3) yes, they cannot, only one thread can be active inside synchronized section guarded by given monitor
4) you don't need to (and you should not use synchronized on method level if you are using explicit synchronization). BUT its better (for libraries/large codebase), because then you can controll who can acces instance on which synchronization occurs, so someone other can't synchronize on it and cause deadlock.
Does Thread lock on object ensures lock on member objects too?
No.
I understand that if thread1 is executing set(...) method then any other thread (lets say thread2) is okay to execute either of the anotherSetWithSynchronized
Yes, unless myObject has the same value as 'this'.
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.
This question already has answers here:
Is there an advantage to use a Synchronized Method instead of a Synchronized Block?
(23 answers)
Closed 5 years ago.
What is the difference between a synchronized method and synchronized block in Java ?
I have been searching the answer on the Net, people seem to be so unsure about this one :-(
My take would be there is no difference between the two, except that the synch block might be more localized in scope and hence the lock will be of lesser time ??
And in case of Lock on a static method, on what is the Lock taken ? What is the meaning of a Lock on Class ?
A synchronized method uses the method receiver as a lock (i.e. this for non static methods, and the enclosing class for static methods). Synchronized blocks uses the expression as a lock.
So the following two methods are equivalent from locking prospective:
synchronized void mymethod() { ... }
void mymethod() {
synchronized (this) { ... }
}
For static methods, the class will be locked:
class MyClass {
synchronized static mystatic() { ... }
static mystaticeq() {
syncrhonized (MyClass.class) { ... }
}
}
For synchronized blocks, you can use any non-null object as a lock:
synchronized (mymap) {
mymap.put(..., ...);
}
Lock scope
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). In practice, the JVM is permitted to optimize by removing some operations out of the synchronized block execution if it can prove that it can be done safely.
A synchronized method is shorthand. This:
class Something {
public synchronized void doSomething() {
...
}
public static synchronized void doSomethingStatic() {
...
}
}
is, for all intents and purposes, equivalent to this:
class Something {
public void doSomething() {
synchronized(this) {
...
}
}
public static void doSomethingStatic() {
synchronized(Something.class) {
...
}
}
}
(Where Something.class is the class object for the class Something.)
So indeed, with a synchronized block, you can be more specific about your lock, and more fine-grained about when you want to use it, but other than that there's no difference.
Yes, that is one difference. The other is that you can acquire a lock on other objects than this.
The key difference is this: if you declare a method to be synchronized, then the entire body of the method becomes synchronized; if you use the synchronized block, however, then you can surround just the "critical section" of the method in the synchronized block, while leaving the rest of the method out of the block.
If the entire method is part of the critical section, then there effectively is no difference. If that is not the case, then you should use a synchronized block around just the critical section. The more statements you have in a synchronized block, the less overall parallelism you get, so you want to keep those to the minimum.
A synchronized method locks on the object instance the method is contained in.
Where as a synchronized block can lock on ANY object - typically a mutex obect defined as an instance variable. This allows more control over what locks are in operation.
My take would be there is no difference between the two, except that the synch block might be more localized in scope and hence the lock will be of lesser time ??
Yes. You are right. Unlike synchronized methods, synchronized statements must specify the object that provides the intrinsic lock.
Example from java tutorial:
public void addName(String name) {
synchronized(this) {
lastName = name;
nameCount++;
}
nameList.add(name);
}
Synchronized statements are also useful for improving concurrency with fine-grained synchronization. You can find good example on same tutorial page for below use case.
Suppose, for example, class MsLunch has two instance fields, c1 and c2, that are never used together. All updates of these fields must be synchronized, but there's no reason to prevent an update of c1 from being interleaved with an update of c2 — and doing so reduces concurrency by creating unnecessary blocking. Instead of using synchronized methods or otherwise using the lock associated with this, we create two objects solely to provide locks.
And in case of Lock on a static method, on what is the Lock taken ? What is the meaning of a Lock on Class ?
In this case, the thread acquires the intrinsic lock for the Class object associated with the class. Thus access to class's static fields is controlled by a lock that's distinct from the lock for any instance of the class.
When you make a method as synchronized ( non static ) :
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.
If you make a method as static synchronized :
It is not possible for two invocations of static synchronized methods on different objects of same class to interleave. When one thread is executing a static synchronized method for an object of Class A, all other threads that invoke static synchronized methods on any of objects of Class A block (suspend execution) until the first thread is done with the method execution.
You find better alternatives to synchronization in this SE question:
Avoid synchronized(this) in Java?