Does using ReadWriteLock inside a synchronized method make sense? - java

We have some code that implements a cache. All of the methods have the synchronized keyword, and also use a ReadWriteLock internally. Simplified example:
private final ReadWriteLock _rwLock = new ReadWriteLock();
public synchronized void setItem(final UUID id, final Object someObjToCache) {
try {
_rwLock.writeLock().lock();
_innerCache.set(id, someObjToCache);
} finally {
_rwLock.writeLock().unlock();
}
}
public synchronized Object getItem(final UUID id) {
try {
_rwLock.readLock().lock();
return _innerCache.get(id);
} finally {
_rwLock.readLock().unlock();
}
}
Is there any benefit to using both of these locking techniques? I expect it to be a read-mostly cache, so I would think that just using the ReadWriteLock would be sufficient.

Yes, a ReadWriteLock should be sufficient. Using it with synchronized does not make much sense in this case: synchronized means that only one thread can execute any synchronized method at a time.

Using two locks will only help when you need to lock two resources at once.
I suspect you only need one lock, not two. If you used a concurrent collection you might not need either.
final Map<UUID, Object> cache = new ConcurrentHashMap<>();
public void setItem(UUID id, Object obj) { cache.put(id, obj); }
public Object getItem(UUID id) { return cache.get(id); }

Related

How to synchronize code based on boolean value?

I have this code:
private volatile boolean immortal;
private Object lock = new Object();
public void set(boolean immortal) {
this.immortal = immortal;
}
public void kill() {
// .... contains some other code.
synchronized(lock) {
if (!immortal) {
for (int i = 0; i < numThreads; i++) {
runnableList.add(POISON_PILL);
}
}
}
}
My use case is that I would like the if statement in the kill method to run to completion before immortal value is changed. Is there a better way of doing this without locking on an object?
I mean what is the best way to synchronize a block only if the value of a boolean variable is false and not allow the boolean value to be changed till it runs to completion? Can I achieve this using AtomicBoolean?
A neat way to do this could be to declare your runnableList as a synchronized list:
// where T is whatever type it needs to be
List<T> runnableList = Collections.synchronizedList(new ArrayList<>());
Then you could add to it without explicit synchronization:
if (!immortal) {
runnableList.addAll(Collections.nCopies(numThreads, POISON_PILL));
}
This works because a single call to addAll is atomic.
This isn't doing it without synchronization, though, it's just internal to the list.
With this said, it's hard to recommend a "better" solution because it's not clear what the requirements are. Synchronization (etc) is used to preserve the invariants of your object when operated on by multiple threads.
For example, why do you need immortal to remain unchanged while you add things to runnableList? How else do you access immortal and runnableList? etc
Use two locks:
private boolean immortal;
private final Object killMonitor = new Object();
private final Object flagMonitor = new Object();
public void set(boolean immortal) {
synchronized (flagMonitor) {
this.immortal = immortal;
}
}
public void kill() {
// ...
synchronized (flagMonitor) {
if (!immortal) {
synchronized (killMonitor) {
runnableList.addAll(Collections.nCopies(numThreads, POISON_PILL));
}
}
}
}

How to explicitly hold lock on java object

I have an object that is accessed from multiple threads. I want to implement it so that in order to access its setters and getters, the caller must first explicitly lock it before and then unlock it after finishing. I've though about using synchronized methods but it doesn't seem very straight-forward compared to java's more explicit locking APIs. This is my current stubbed implementation using ReentrantLock.
public class Data {
private ReentrantLock lock;
private int IntValue;
public Data() {
this.IntValue = 0;
this.lock = new ReentrantLock();
}
public void Lock() {
lock.lock();
}
public void Unlock() {
if (!lock.isLocked()) {
return;
}
//only the thread owning the lock can proceed to unlock
lock.lock();
int lockCount = lock.getHoldCount();
for (int i = 0; i < lockCount; i++) {
lock.unlock();
}
}
public void SetVal(int val) {
if (!lock.isLocked()) {
return;
}
lock.lock();
this.IntValue = val;
}
}
So if a thread wants to call SetVal(int val), it would first have to call Lock() and then call Unlock() when it's done. I've placed isLocked() checks in its setter/getter methods to enforce this rule. And I've added an additional lock call in unlock to make sure only the thread owning the lock can proceed to unlock (an unique feature of ReentrackLock). The object's setters/getters could be called many times before its Unlock() method is called. So in the Unlock() method I have to iterate through its HoldCount and unlock for each count.
I'm wondering if there is a more efficient and idiomatic way of achieving this?
If you are only using int value then can go for AtomicInteger
or make all your method synchronized that you want to prevent from race condition.
or if you want to support both synchronized and normal then you can pit a wrapper like collections.SynchronizedSet.Hope this will help.
You are running into the wrong direction with your approach. OOP paradigms state that all data should be kept and managed internally, what you do however is to externalize that control over the internal data by giving it to the caller.
A good design would try to hide the fact that locking is even necessary and do it internally to free the caller from such tasks. Especially because if you transfer the responsibility of proper locking to the caller, then every single caller could be a potential thread issue. If you lock internally however, there is only a single source of potential bugs, so if you encounter an issue you know where to look.
This is how you would do it properly regarding the OOP paradigm:
public class Data {
// protected so it is accessible to derived classes
// final so the lock object cannot be (accidentally) reassigned
// Lock (base class) so it is easier to change the implementation later
protected final Lock lock;
// clear naming
private int value;
public Data() {
// value is automatically initialized with 0
this.lock = new ReentrantLock();
}
// by convention the setter for ... is set...
public void setValue(final int value) {
this.lock.lock();
// absolutely use try/finally here, to ensure it is unlocked in all cases
try {
this.value = value;
} finally {
this.lock.unlock();
}
}
// by convention the getter for ... is get...
public int getValue() {
this.lock.lock();
try {
return this.value;
} finally {
this.lock.unlock();
}
}
}

Convert double check locking from using synchronized to locks in JAVA

Consider the following code implementing double check locking using the synchronized keyword in JAVA 8:
private static void redoHeavyInitialisation() {
if (needToReinitialise()) {
synchronized (MyClass.class) {
if (needToReinitialise()) {
doHeavyInitialisation();
}
}
}
}
The reason double check locking is used is because the initialisation is heavy (hence lazy) AND it can happen more than once (hence singleton pattern can not be used, correct me if I am wrong).
Anyway, first, how do you convert the code above to use Lock from the JAVA concurrent package instead of using synchronized keyword?
Only after that AND optionally, feel free to comment on using Lock or synchronized keyword which one is better.
Remember, this question is not about Lock vs synchronized comparison. Answer attempts without answering the code conversion part will not be picked as accepted answer.
Transformation of synchronized blocks to the equivalent block using ReentrantLock is pretty rote.
First you create a lock with the same or similar scope and lifetime as the object you were locking on. Here you are locking on MyClass.class, hence a static lock, so you can map this to a static lock in MyClass, such as MyClass.initLock.
Then just replace each:
synchronized (object) {
with
lock.lock();
try {
and each associated closing brace with
} finally {
lock.unlock();
}
Putting it all together you have:
private final static ReentrantLock initLock = new ReentrantLock();
private static void redoHeavyInitialisation() {
if (needToReinitialise()) {
MyClass.initLock.lock();
try {
if (needToReinitialise()) {
doHeavyInitialisation();
}
} finally {
MyClass.initLock.unlock();
}
}
}
Performance-wise there is little daylight between the approaches. They essentially have the same semantics and usually use similar underlying mechanisms. In the past, there have been performance differences - sometimes optimizations have gone in that affect one or the other, so on some JVMs you can find a difference, but the whole point of double checked locking is to avoid taking the lock anyway, so just do what's simplest. You only get the lock for a very small transitory period while the needToReinitialise() method is running, so the locking cost won't have any ongoing impact.
Consider the following code:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HeavyInitializer {
static final Logger logger = LoggerFactory.getLogger(HeavyInitializer.class);
static HeavyInitializer singleton;
public static synchronized HeavyInitializer getInstance() {
if (singleton==null) {
singleton = new HeavyInitializer();
}
return singleton;
}
boolean initialized;
private HeavyInitializer() {
initialized = false;
}
public synchronized void initialize() {
if (!initialized) {
heavyStuffDoneHere();
}
}
public synchronized void reInitilize() {
if (needToReinitialise()) {
heavyStuffDoneHere();
}
}
private void heavyStuffDoneHere() {
initialized = true;
}
private boolean needToReinitialise() {
if (!initialized)
return false;
boolean ret = false;
//Do your check here... and set ret
return ret;
}
}
From Oracle's doc:
... 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.
Trying to use Lock would be trying to reimplement the synchronized block. Not necessary.
Singleton Double checks the lock and prevents singleton object to break using serialization.
package pattern.core.java;
import java.io.Serializable;
public class Singleton extends Object implements Serializable {
private static final long serialVersionUID = 1L;
private static Singleton sg;
private Singleton() {
}
public static Singleton getSingletonObj() {
if (sg == null) {
synchronized (sg) {
if (sg == null) {
sg = new Singleton();
}
}
}
return sg;
}
/*
* this method ensures that new object will not be created for singleton
* class using serialization and deserialization
*/
protected Object readResolve() {
return sg;
}
/*
* #Override protected Object clone() throws CloneNotSupportedException {
* throw new CloneNotSupportedException(); }
*/
#Override
protected Object clone() throws CloneNotSupportedException {
return sg;
}
}

Java synchronized statement

I need a threadsafe arraylist like this.
public class BookingList {
private List<Booking> bookings;
public BookingList() {
bookings = Collections.synchronizedList(new ArrayList<Booking>());
}
#Override
public void addBooking(Booking booking)
{
synchronized (bookings) {
bookings.add(booking);
}
}
#Override
public void removeBooking(Booking booking)
{
synchronized (bookings) {
bookings.remove(booking);
}
}
}
According to java doc, when using Collections.synchronizedList one needs to synchronize each access to the list. I'm not sure whether my synchronized blocks will do this?
Is my use of synchronized blocks equivalent to
...
public synchronized void addBooking(Booking booking) {
bookings.add(booking);
}
Should I use a ReentrantLock like this
private Lock lock = new ReentrantLock();
public void addBooking(Booking booking) {
try {
lock.lock;
bookings.add(booking);
} finally {
lock.release();
}
}
You don't need to synchronize simple operations like add or remove because this is handled internally by the implementation and this is precisely why you use them: to avoid handling the synchronization yourself
But for composite operations like iterations or multiple removal that are out of the scope of the internal synchronization you must provide your own locking mechanism.
To answer your questions:
1:
public synchronized void addBooking(Booking booking) {
bookings.add(booking);
}
is equivalent to
public void addBooking(Booking booking) {
synchronized (this){
bookings.add(booking);
}
}
2: for your example you should not use ReentrantLock. Calling methods of a list that has been initialized with Collections.synchronizedList() is thread-safe, no further synchronized or other locking mechanisms have to be used. For the rest see #Pragmateek's answer.

How to avoid Nested synchronization and the resulting deadlock

I need to lock two objects in a functionality and the current code looke like this;
Object obj1 = ...//get from somewhere
Object obj2 = ...//get from somewhere
synchronized(obj1){
...//blah
synchronized(obj2){
...//blah
}
}
As you can see this is a plain and straight recipe for deadlocks if another thread runs this piece of code with obj1 and two reversed.
Is there a way to avoid this situation using concurrency-utils locks?
I was contemplating maintaining a map of objects and their locks and verifying if they were available to take, but can't seem to come up with a clean way which will predict the lock order.
Although you preserve locking order, if obj1 is switched with obj2 you'll run into deadlock.
You must look for another solution to avoid this cases: lock ordering + optional tie breaking lock
int fromHash = System.identityHashCode(obj1);
int toHash = System.identityHashCode(obj2);
if (fromHash < toHash) {
synchronized (obj1) {
synchronized (obj2) {
........
}
}
} else if (fromHash > toHash) {
synchronized (obj2) {
synchronized (obj1) {
........
}
}
} else {
synchronized (TIE_LOCK) {
synchronized (fromAcct) {
synchronized (toAcct) {
...
}
}
}
Depending on what you are doing you may be able to take what you want from the first locked object and use that information to process the second locked object. e.g.
instead of
synchronized(list1) {
for(String s : list1) {
synchronized(list2) {
// do something with both lists.
}
}
}
do this
List<String> listCopy;
synchronized(list1) {
listCopy = new ArrayList<String>(list1);
}
synchornized(list2) {
// do something with liastCopy and list2
}
You can see you only have lock at a time so you won't get a deadlock.
You need to consistently lock in the order of obj1 and then obj2. If you never violate this order, you won't have deadlocks.
Essentially what you have is the dining philospher's problem.
https://en.wikipedia.org/wiki/Dining_philosophers_problem
Ovidiu Lupas's answer is similar to Dijkstra's Resource Heirarchy solution, but there are 3 more solutions, explained on the wiki page
This is what the arbitrator solution looks like. If all of the objects which you're operating from inherit from the same type, you could use static class variables to implement the arbitrators on the class of objects.
import java.util.concurrent.locks.Lock;
public void init()
{
Lock arbitrator = new Lock();
}
public void meth1()
{
arbitrator.lock();
synchronized (obj1) {
synchronized (obj2) {
arbitrator.unlock();
// Do Stuff
}
}
}
public void meth2()
{
arbitrator.lock();
synchronized (obj2) {
synchronized (obj1) {
arbitrator.unlock();
// Do Stuff
}
}
}
The Chandy/Misra solution requires a lot of message passing so I'm not going to implement it, but wikipedia has a pretty good explaination
You can solve it in other way I suppose.
class Obj implements Comparable<Obj> {
// basically your original class + compare(Obj other) implementation
}
class ObjLock implements Lock, Comparable<ObjLock> {
private final Lock lock;
private final Obj obj; // your original object
ObjLock(Obj obj) {
this.obj = obj;
this.lock = new ReentrantLock();
}
#Override
public int compare(ObjLock other) {
return this.obj.compare(other.obj); // ObjLock comparison based on Obj comparison
}
// + reimplement Lock methods with this.lock invocations
}
Then do
class ObjLocksGroup {
private final List<ObjLock> objLocks;
ObjLocksGroup(ObjLock... objLocks) {
this.objLocks = stream(objLocks)
.sorted() // due to ObjLock implements Comparable and sorting you are sure that order of ObjLock... will always be the same
.collect(toList));
}
void lock() {
this.objLocks.forEach(ObjLock::lock);
}
void unlock() {
this.objLocks.forEach(ObjLock::unlock);
}
}
And use it as you want:
ObjLocksGroup locks = new ObjLocksGroup(obj1, obj2) // the same as obj2, obj1, order does not matter anymore.
locks.lock();
locks.unlock();

Categories