Does deadlock happen per method or per class? - java

Immagine that I have Class First with several synchronised methods. When a thread locks the class First, does it lock per method or per class? For example does deadlock happen for the following code?
public class DeadLockQuestion {
public static class First{
public synchronized void a(){
}
public synchronized void b(){
}
public synchronized void c(){
}
public synchronized void d(){
}
public synchronized void e(){
}
}
public static void main(String... args){
First f = new First();
//This code is run in Thread 1
f.a();
// End
//This code is run in Thread 2 simultanously
f.b();
//End
// We have also Threads 3 & 4 & 5 that invoke c,d and e simultanously
}
}

You have got two locks in Java. One is Object lock. and the other is Class Lock.
The object lock locks access to synchronized non-static functions only. and Class lock locks on synchronized static functions only.
For you, its an object lock on object f. So all the synchronized non-static functions are locked for object f.
Since all the Threads are using the same object f, Only one Thread will be able to access your non-static functions a(), b(),... at a time.
Read more here
does deadlock happen for the following code?
No, it won't happen in your case. Because While one Thread is holding the lock, Other threads can't get inside your synchronized function.DeadLock happens due to resources.
You have only one resource thats Object f. There's no point of a dead-lock here because the class First doesn't lock another object and no cyclic lock can happen. Deadlock requires a cyclic lock!
Some Info:
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.
These methods or blocks can be static or non-static both.
When ever a thread enters into java synchronized method or block it
acquires a lock and whenever it leaves java synchronized method or
block it releases the lock. Lock is released even if thread leaves
synchronized method after completion or due to any Error or
Exception.
It’s possible that both static synchronized and non static
synchronized method can run simultaneously or concurrently because
they lock on different object.
Useful Source Here, and here

Deadlock happens to threads, not to methods or classes.
The deadlocked threads also hold locks, but in this case it is impossible to tell which locks because you do not demonstrate an actual deadlock scenario (if two threads call synchronized methods of f one goes through and the other waits; deadlock requires at least two locks).

To lock each method independently use a synchronized block within each method and lock on a different object.
If you have an appropriate (and it should be final to prevent potential problems) object already within the class you can use that. If not create a private final Object aLock = new Object(); and then lock on that, for example:
private final Object aLock = new Object();
public void a() {
synchronized(aLock) {
// Do stuff that needs the lock
}
// do stuff that doesn't need the lock
}
Always hold the lock for as long as you need it, but no longer.

When a() is a synchronized method, f.a() literally means:
synchronized(f){
f.a();
}
So in this case a lock would happen for object monitor f. In your case you would require a second object to create a deadlock, I don't think it's possible to create a deadlock with a single object monitor. A typical deadlock pattern is when an order of lock acquisition is not being maintained, i.e. when this happens in two different threads:
synchronized(a){
synchronized(b){
...
}
}
// and
synchronized(b){
synchronized(a){
...
}
}

Firstly, Deadlock occurs with threads and not classes or methods.
Deadlock occurs when there is a cyclic dependency of locks.
Thread A ---> locks L1 ---> tries to lock L2
Thread B ----> locks L2 ------> tries to lock L1
Image source: FusionReactor deadlock plugin

Related

What exactly is "re-entrant" in a Reentrant lock in Java? [duplicate]

Reentrancy means that locks are acquired on a per-thread rather than per-invocation basis.
Since an intrinsic lock is held by a thread, doesn't it mean that a thread run once equals an invocation basis?
Thank you, it seems mean that: in a thread,if I get a lock lockA when process function doA which call function doB, and doB also need a lock lockA,then there wil be a reentrancy. In Java, this phenomenon is acquired per thread, so I needn't consider deadlocks?
Reentrancy means that locks are acquired on a per-thread rather than per-invocation basis.
That is a misleading definition. It is true (sort of), but it misses the real point.
Reentrancy means (in general CS / IT terminology) that you do something, and while you are still doing it, you do it again. In the case of locks it means you do something like this on a single thread:
Acquire a lock on "foo".
Do something
Acquire a lock on "foo". Note that we haven't released the lock that we previously acquired.
...
Release lock on "foo"
...
Release lock on "foo"
With a reentrant lock / locking mechanism, the attempt to acquire the same lock will succeed, and will increment an internal counter belonging to the lock. The lock will only be released when the current holder of the lock has released it twice.
Here's a example in Java using primitive object locks / monitors ... which are reentrant:
Object lock = new Object();
...
synchronized (lock) {
...
doSomething(lock, ...)
...
}
public void doSomething(Object lock, ...) {
synchronized (lock) {
...
}
}
The alternative to reentrant is non-reentrant locking, where it would be an error for a thread to attempt to acquire a lock that it already holds.
The advantage of using reentrant locks is that you don't have to worry about the possibility of failing due to accidentally acquiring a lock that you already hold. The downside is that you can't assume that nothing you call will change the state of the variables that the lock is designed to protect. However, that's not usually a problem. Locks are generally used to protect against concurrent state changes made by other threads.
So I needn't consider deadlocks?
Yes you do.
A thread won't deadlock against itself (if the lock is reentrant). However, you could get a deadlock if there are other threads that might have a lock on the object you are trying to lock.
Imagine something like this:
function A():
lock (X)
B()
unlock (X)
function B():
A()
Now we call A. The following happens:
We enter A, locking X
We enter B
We enter A again, locking X again
Since we never exited the first invocation of A, X is still locked. This is called re-entrance - while function A has not yet returned, function A is called again. If A relies on some global, static state, this can cause a 're-entrance bug', where before the static state is cleaned up from the function's exit, the function is run again, and the half computed values collide with the start of the second call.
In this case, we run into a lock we are already holding. If the lock is re-entrance aware, it will realize we are the same thread holding the lock already and let us through. Otherwise, it will deadlock forever - it will be waiting for a lock it already holds.
In java, lock and synchronized are re-entrance aware - if a lock is held by a thread, and the thread tries to re-acquire the same lock, it is allowed. So if we wrote the above pseudocode in Java, it would not deadlock.
Java concurrency in practice book states - Reentrancy means that locks are acquired on a per-thread rather than per-invocation basis.
Let me explain what it exactly means. First of all Intrinsic locks are reentrant by nature. The way reentrancy is achieved is by maintaining a counter for number of locks acquired and owner of the lock. If the count is 0 and no owner is associated to it, means lock is not held by any thread. When a thread acquires the lock, JVM records the owner and sets the counter to 1.If same thread tries to acquire the lock again, the counter is incremented. And when the owning thread exits synchronized block, the counter is decremented. When count reaches 0 again, lock is released.
A simple example would be -
public class Test {
public synchronized void performTest() {
//...
}
}
public class CustomTest extends Test {
public synchronized void performTest() {
//...
super.performTest();
}
}
without reentrancy there would be a deadlock.
Reentrancy means that locks are acquired on a per-thread rather than per-invocation basis.
Let me explain this with an example.
class ReentrantTester {
public synchronized void methodA() {
System.out.println("Now I am inside methodA()");
methodB();
}
public synchronized void methodB() {
System.out.println("Now I am inside methodB()");
}
public static void main(String [] args) {
ReentrantTester rt = new ReentrantTester();
rt.methodA();
}
}
The out put is :
Now I am inside methodA()
Now I am inside methodB()
As in the above code, the ReentrantTester contains two synchronized methods: methodA() & methodB()
The first synchronized method methodA() calls the other synchronized method methodB().
When execution enters the methodA(), the current thread acquires the monitor for the ReentrantTester object.
Now when methodA() calls methodB(), because methodB() is also synchronized, the thread attempts to acquire the
same monitor again. Because Java supports reentrant monitors, this works. The current thread acquire the ReentrantTester's
monitor again and continue the execution of both methodA() and methodB().
The Java runtime allows a thread to reacquire a monitor that it already holds, because Java monitors are
reentrant. These reentrant monitors are important because they eliminate the possibility of a single thread
deadlocking itself on a monitor that it already holds.
This just means once a thread has a lock it may enter the locked section of code as many times as it needs to. So if you have a synchronized section of code such as a method, only the thread which attained the lock can call that method, but can call that method as many times as it wants, including any other code held by the same lock. This is important if you have one method that calls another method, and both are synchronized by the same lock. If this wasn't the case the. The second method call would block. It would also apply to recursive method calls.
public void methodA()
{
// other code
synchronized(this)
{
methodB();
}
}
public void methodB()
{
// other code
syncrhonized(this)
{
// it can still enter this code
}
}
it's about recurse, think about:
private lock = new ReentrantLock();
public void method() {
lock.lock();
method();
}
If the lock is not re-entrant able, the thread could block itself.

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.
Is there a difference between the two options in the code?
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()).
if I do a synchronized block in some place in the code, does it lock only the synchronized block or all the "this" code?
From here down EDIT: thank you all, it was very helpful, but I have a few more questions following your answers.
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)?
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).
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)?
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)
`
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.
Yes there is a difference in the options. In the above option, two threads cannot call getCount() at the same time, in the below one they can.
Yes, that is correct. There can only be one thread at the same time holding a lock on an object.
Each object has its own lock. So it lock all synchronized (this) block of that object.
Note, however, that each object has a lock of its own and also each class has a lock of its own. In the constructor you use the object lock to access a static (class) variable, while in getCount() you use the class lock. That means that your code is not thread-safe!
synchronized steps:
Check if object lock is already acquired. If so, proceed into synchronized block/method
Attempt to aquire lock. If the lock has already been acquired by another thread, then the thread will wait for the lock to be released, at which point it will go through the cycle (2.) again
Is there a difference between the two options in the code?
Yes, there is clear difference. In first, you are synchronizing threads access to getCount() method on the class object of ObjectCounter. While in second you are not.
If I lock "this" shouldn't it means that I can't call getCount() until
the contractor exit the synchronized block (lets say if I don't write
synchronize on the getCount()).
Since there is only one lock of an object (class locks are different which are held through using static keyword along with synchronized), so if some other thread is acquiring that lock either because of synchronized(this){ or because of this synchronized long getCount(){ then the new thread trying to acquire the lock has to wait until the previous thread has released the lock.
Now since in your case, you are doing, static synchronized long getCount(){, so, its locking becomes different from synchronized(this){. Which means that if some thread is acquiring a lock because of synchronized(this){ and some other thread is trying to invoke getCount() then that thread will not be blocked.
if I do a synchronized block in some place in the code, does it locks
the only the synchronized block or all the "this" code?
Non-static synchronization:
If you do synchronized block in some place in the code and it is non-static public synchronized long getCount(){, then also the lock of your object will be held, so new thread trying to acquire the lock has to wait until the previous thread has released the lock.
Static synchronization:
If you do synchronized block in some place in the code and it is static public static synchronized long getCount(){, then it will have no effect on lock of non-static sychronization.
Bottom line:
There is only and only one lock for one object, and if that lock is acquired by some thread then other threads has to wait until that lock released.
Then there is a class lock, which is held if static keyword is used along with synchronized keyword.

What is the meaning of "ReentrantLock" in Java?

Reentrancy means that locks are acquired on a per-thread rather than per-invocation basis.
Since an intrinsic lock is held by a thread, doesn't it mean that a thread run once equals an invocation basis?
Thank you, it seems mean that: in a thread,if I get a lock lockA when process function doA which call function doB, and doB also need a lock lockA,then there wil be a reentrancy. In Java, this phenomenon is acquired per thread, so I needn't consider deadlocks?
Reentrancy means that locks are acquired on a per-thread rather than per-invocation basis.
That is a misleading definition. It is true (sort of), but it misses the real point.
Reentrancy means (in general CS / IT terminology) that you do something, and while you are still doing it, you do it again. In the case of locks it means you do something like this on a single thread:
Acquire a lock on "foo".
Do something
Acquire a lock on "foo". Note that we haven't released the lock that we previously acquired.
...
Release lock on "foo"
...
Release lock on "foo"
With a reentrant lock / locking mechanism, the attempt to acquire the same lock will succeed, and will increment an internal counter belonging to the lock. The lock will only be released when the current holder of the lock has released it twice.
Here's a example in Java using primitive object locks / monitors ... which are reentrant:
Object lock = new Object();
...
synchronized (lock) {
...
doSomething(lock, ...)
...
}
public void doSomething(Object lock, ...) {
synchronized (lock) {
...
}
}
The alternative to reentrant is non-reentrant locking, where it would be an error for a thread to attempt to acquire a lock that it already holds.
The advantage of using reentrant locks is that you don't have to worry about the possibility of failing due to accidentally acquiring a lock that you already hold. The downside is that you can't assume that nothing you call will change the state of the variables that the lock is designed to protect. However, that's not usually a problem. Locks are generally used to protect against concurrent state changes made by other threads.
So I needn't consider deadlocks?
Yes you do.
A thread won't deadlock against itself (if the lock is reentrant). However, you could get a deadlock if there are other threads that might have a lock on the object you are trying to lock.
Imagine something like this:
function A():
lock (X)
B()
unlock (X)
function B():
A()
Now we call A. The following happens:
We enter A, locking X
We enter B
We enter A again, locking X again
Since we never exited the first invocation of A, X is still locked. This is called re-entrance - while function A has not yet returned, function A is called again. If A relies on some global, static state, this can cause a 're-entrance bug', where before the static state is cleaned up from the function's exit, the function is run again, and the half computed values collide with the start of the second call.
In this case, we run into a lock we are already holding. If the lock is re-entrance aware, it will realize we are the same thread holding the lock already and let us through. Otherwise, it will deadlock forever - it will be waiting for a lock it already holds.
In java, lock and synchronized are re-entrance aware - if a lock is held by a thread, and the thread tries to re-acquire the same lock, it is allowed. So if we wrote the above pseudocode in Java, it would not deadlock.
Java concurrency in practice book states - Reentrancy means that locks are acquired on a per-thread rather than per-invocation basis.
Let me explain what it exactly means. First of all Intrinsic locks are reentrant by nature. The way reentrancy is achieved is by maintaining a counter for number of locks acquired and owner of the lock. If the count is 0 and no owner is associated to it, means lock is not held by any thread. When a thread acquires the lock, JVM records the owner and sets the counter to 1.If same thread tries to acquire the lock again, the counter is incremented. And when the owning thread exits synchronized block, the counter is decremented. When count reaches 0 again, lock is released.
A simple example would be -
public class Test {
public synchronized void performTest() {
//...
}
}
public class CustomTest extends Test {
public synchronized void performTest() {
//...
super.performTest();
}
}
without reentrancy there would be a deadlock.
Reentrancy means that locks are acquired on a per-thread rather than per-invocation basis.
Let me explain this with an example.
class ReentrantTester {
public synchronized void methodA() {
System.out.println("Now I am inside methodA()");
methodB();
}
public synchronized void methodB() {
System.out.println("Now I am inside methodB()");
}
public static void main(String [] args) {
ReentrantTester rt = new ReentrantTester();
rt.methodA();
}
}
The out put is :
Now I am inside methodA()
Now I am inside methodB()
As in the above code, the ReentrantTester contains two synchronized methods: methodA() & methodB()
The first synchronized method methodA() calls the other synchronized method methodB().
When execution enters the methodA(), the current thread acquires the monitor for the ReentrantTester object.
Now when methodA() calls methodB(), because methodB() is also synchronized, the thread attempts to acquire the
same monitor again. Because Java supports reentrant monitors, this works. The current thread acquire the ReentrantTester's
monitor again and continue the execution of both methodA() and methodB().
The Java runtime allows a thread to reacquire a monitor that it already holds, because Java monitors are
reentrant. These reentrant monitors are important because they eliminate the possibility of a single thread
deadlocking itself on a monitor that it already holds.
This just means once a thread has a lock it may enter the locked section of code as many times as it needs to. So if you have a synchronized section of code such as a method, only the thread which attained the lock can call that method, but can call that method as many times as it wants, including any other code held by the same lock. This is important if you have one method that calls another method, and both are synchronized by the same lock. If this wasn't the case the. The second method call would block. It would also apply to recursive method calls.
public void methodA()
{
// other code
synchronized(this)
{
methodB();
}
}
public void methodB()
{
// other code
syncrhonized(this)
{
// it can still enter this code
}
}
it's about recurse, think about:
private lock = new ReentrantLock();
public void method() {
lock.lock();
method();
}
If the lock is not re-entrant able, the thread could block itself.

Java Threading - Synchronized code

Why do you have to specify, which object has locked a synchronized block of code?
You don't have to specify which object has locked a synchronized method as it is always locked by 'this' (I believe).
I have two questions:
Why can't you block a none static method with an object other than
'this' ?
Why do you have to specify the object that has blocked
synchronized code?
I have read chapter nine of SCJP for Java 6, but I am still not clear on this.
I realize it is probably a basic question, but I am new to Threading.
Why can't you block a none static method with an object other than 'this' ?
You can:
public void foo() {
synchronized (lock) {
...
}
}
Why do you have to specify the object that has blocked synchronized code?
Because that's how the language designers chose to design the language. synchronized, when used on instance methods, implicitely uses this as the lock. synchronized when used on a block must explicitely specify the lock.
You can.
The code
synchronized foo() {
// some stuff
}
Is logically equal to code
foo() {
synchronized(this) {
// some stuff
}
}
I said "logically" because these 2 examples generate different byte code.
If method foo() is static synchronization is done of class object.
However you can wish to create several synchronized blocks that are synchronized on different objects into one class or even into one method. In this case you can use synchronized (lock) where lock is not this:
foo() {
synchronized(one) {}
///..........
synchronized(two) {}
}
You can specify any object you want which should have the lock on the synchronized code block. Actually, you shouldn't use synchronize(this) at all (or maybe be careful about it, see Avoid synchronized(this) in Java?).
EVERY object has a lock on which you can synchronize:
final Object lock = new Object()
synchronized ( lock ) { ... }
If you want to synchronize the whole method, you cannot say on which object, so it is always "this" object.
synchronized foo() {....}
The first way of locking is better, by the way.
It is not recommended to lock each method with this as it reduces the concurrency in most cases. So it is recommended to use Lock Stripping in which only the specific part of the code that needs to be protected is kept in synchronized block.
It is a practice that is explained well in Java Concurrency in Practice. But note this book is useful only when you have some basic experience with threading.
Some nuggets to keep in mind:
Do not overuse synchronization
use method level synchronization only when the whole method needs to be protected
Use different locks to protect two unrelated entities, which will increase the chances of concurrency. or else for reading or writing two unrelated entities threads will block on same lock.
public void incrementCounter1(){
synchronized(lockForCounter1){
counter1++;
}
}
public void incrementCounter2(){
synchronized(lockForCounter2){
counter2++;
}
}
I think your two questions actually are same. let's say if you wanna synchronized a method m of object a between multiple threads, you need a common base system or channel that threads can talk to, this is actually what object lock offers, so when you wanna a method of a object be synchronized there is no need for another object lock to do this, because the object you access itself has this lock, that's how and why lanuage designed.
while synchronized a block is not the same thing, threads can have different talking base other than this object itself, for instance, you can set a same object as synchronized object lock for synchronized block, so all objects of this Class can be synchronized at that block!
From the concurrency tutorial, the Synchronized methods part:
To make a method synchronized, simply add the synchronized keyword to its declaration:
public class SynchronizedCounter {
private int c = 0;
public synchronized void increment() {
c++;
}
public synchronized void decrement() {
c--;
}
public synchronized int value() {
return c;
}
}
If count is an instance of SynchronizedCounter, then 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.
Simply put, that's how synchronization in Java works.
You don't have to specify which object has locked a synchronized method as it is always locked by 'this' (I believe).
True for instance methods, for static methods it locks upon the class object.
Why can't you block a none static method with an object other than 'this' ?
Note that:
public synchronized void increment() {
c++;
}
is equivalent in behavior to:
public void increment() {
synchronized(this) {
c++;
}
}
In this code snippet you can replace this with any object you wish.
Why do you have to specify the object that has blocked synchronized code?
Some, let's call it critical, block of code is to be ran only sequentially, but in uncontrolled concurrent environment it is possible that it will be ran in parallel. That's why synchronization mechanisms exists.
So we can divide the code like this:
the code safe to be ran in parallel (default situation)
the code that has to be synchronized (must be marked somehow)
That markation is made via the synchronized keyword and the corresponding lock object.
If you have two different critical code blocks that must not be ran together, they'll both have the synchronized keyword, and let's say they have the same lock object.
While the first block is executing, the lock object becomes "locked". If during that time the second block needs to get executed, the first command of that code block is:
synchronized(lock) {
but that lock object is in locked state because the first block is executing. The execution of the second block halts on that statement until the first block finishes the execution, and unlocks the state of the lock object. Then the second block may proceed with the execution (and lock the lock object again).
That mechanism is called the mutual exclusion and the lock is a general concept not tied to the Java programming language.
The details of the "lock object locking" process can be found here.
You can lock with any instance of an object but programmers usually
use this or locker...
Because it restrict access to that part of code by other threads
(unit of code processing) so you make sure whole of that part run in
consistence and nothing (i.e. a variable) would be alerted by another thread.
Consider:
a = 1;
a++;
Thread one reaches second line and you expect a = 2 but another thread executes first line and instead of 2 you have a = 1 for first thread and a = 2 for second thread. Now:
synchronized (whatever)
{
a = 1;
a++;
}
Now second thread would be blocked from entering into the code block (synchronized body) until first one leaves it (release the lock).

Synchronized threads and locking

Can someone please explain the difference between these two examples in the context of object locking:
public void method1(){
synchronized(this){
....
}
}
And
StringBuffer aStringBufferObject = new StringBuffer("A");
public void method2(){
synchronized(aStringBufferObject){
....
}
}
I know the first example will obtain a lock on the this instance and the second will obtain a lock of the aStringBufferObject instance. But i dont really understand what the effect or the difference of the two is.
For example, in the second example, will threads still be able to execute the code inside the synchronized block because the lock is not related to the 'this' instance?
I know that synchronizing a method or a block of code prevents multiple threads to access that block/method at the same time but what is the purpose of specifying the object to lock on and what is the difference in the way the object is specified as in the above examples?
What is the purpose of specifying the object to lock on?
Often, it is easier to synchronize on this or on the Class instance (for static methods). But, there are cases where you will need to synchronize on a specific object instead of the implicit lock (this). Such cases include:
You want to synchronize access to primitives without using this. You can only synchronize on Objects as each Object is associated with an implicit monitor in Java. Primitives do not have such implicit monitors, and therefore you need to use a lock object. Using the wrapper classes are a poor and incorrect choice, especially if you end up modifying the lock object in the guarded block.
You want to synchronize on an object that actually protects the critical section, when synchronizing on this would not offer a guarantee of thread safety. For instance, if you are synchronizing access to a ArrayList instance shared across instances of class A, then synchronizing on an instance of A is useless. A thread might create a new instance of A and gain access to the list, while another thread is modifying it. If you use a different lock that all threads must contend for then you can protect the list; this lock could be the one associated with A.class, but it could be any object that will offer the same guarantees.
You want to perform lock splitting to ensure that different guarded blocks are protected by different locks instead of the same lock. In other words, if it is thread-safe to allow different threads to acquire different locks to access different critical sections, then you can have a different lock for every critical section.
The following is an example of split lock usage:
private Object method1Lock = new Object();
private Object method2Lock = new Object();
public void method1(){
synchronized(method1Lock){
....
}
}
public void method2(){
synchronized(method2Lock){
....
}
}
You would use split locks when you can ensure that the concurrent execution of method1 and method2 do not violate the class invariants. This way, you can improve performance across threads that need access to the same object, but will be invoking different methods.
On your other question,
For example, in the second example, will threads still be able to execute the code inside the synchronized block because the lock is not related to the 'this' instance?
In the second example, any thread entering the guarded region must acquire the lock associated with aStringBufferObject. If a different thread is holding that lock, then the current thread will not proceed further. When you specify this, then the thread must acquire the lock associated with the current object. In both cases, a thread must acquire a lock; the examples are only different in the object that is being used as a lock.
Synchronizing on an object means that other blocks which synchronize on the same object will have to wait. For example:
public void methodA() {
synchronized(obj) {
//Do one job
}
}
public void methodB() {
synchronized(obj) {
//Do another job
}
}
If you call methodA() in one thread and then call methodB() in another thread, methodB() won't finish before methodA() finishes.
The synchronized block is a monitor, which leave out of details to lock and unlock a mutex. Because every object in Java has an internal lock(refer to source code of Object class), when use synchronized statement, the JVM will help you synchronize the critical section. You can also synchronize block yourself use ReentrantLock in package java.util.concurrent.locks.

Categories

Resources