Reputation: 7134
Learning about threads and concurrency. Consider the following code:
class A {
protected final Object lock = new Object();
public void remove(Object obj){
synchronized(lock){
// remove the object
}
}
public void add(Object obj){
synchronized(lock){
// add the object
}
}
}
This code is thread-safe in the sense that no two different threads can add
or remove
while one thread is in the process of adding or removing.
Now consider the following sublcass of A:
class B extends A {
public void update1(Object original, Object newObj){
remove(original);
add(original);
}
public void update2(Object original, Object newObj){
synchronized(lock) {
remove(original);
add(newObj);
}
}
}
Class B
must implement a thread-safe update
method. Now, as far as I know update1
is not thread safe because the operation is not atomic, i.e. there is no synchronization between the execution of remove
and add
(correct me if wrong).
Is update2
the correct way to implement a thread-safe update
method?
Are there any disadvantages of having nested synchronized blocks over the same lock
?
Upvotes: 4
Views: 1995
Reputation: 113
The lock is re entrant unless you would be seeing deadlocks every where
Re-entrant lock is the lock which can be reaquired even if the lock is already attained by the same thread.
Why wont you provide the removeAndAdd in the Super class method if there is a scenario which must have remove and add atomic .
Make sure your lock object is marked private and final for security reasons.
Upvotes: 0
Reputation: 43013
The use of synchronized
makes the whole object "locked": no other threads can call any methods while another thread is running one of the object synchronized methods.
This behavior can really slow some program.
As an alternative, you can use ReentrantLock
.
Here is how it applies for the code in the post:
class A {
protected final Lock lock = new ReentrantLock();
public void remove(Object obj){
lock.lock();
try {
// remove the object
} finally {
lock.unlock();
}
}
public void add(Object obj){
lock.lock();
try {
// add the object
} finally {
lock.unlock();
}
}
}
class B extends A {
// ...
public void update2(Object original, Object newObj){
lock.lock();
try {
remove(original);
add(newObj);
} finally {
lock.unlock();
}
}
}
Upvotes: -1
Reputation: 200138
Is
update2
the correct way to implement a thread-safe update method?
Yes, it is. You have achieved atomicity and you are compatible with callers of the individual add
and remove
methods.
Are there any disadvantages of having nested synchronized blocks over the same lock?
No, because the locks are reentrant, meaning the second acquisition doesn't do anything more than remember that the lock was acquired once more, so it doesn't get released until two release actions are performed.
Upvotes: 10