I am looking for a way to combine functionality from synchronized
with functionality from java.util.concurrent.locks.ReentrantReadWriteLock
. More specifically, I would like one method to lock only if the WriteLock
is set, but I want the lock to be on an object variable like synchronized
. Here are examples that will help explain:
ReentrantReadWriteLock Example
public void methodOne(String var) {
lock.writeLock().lock;
try {
// Processing
}
finally {
lock.writeLock().unlock();
}
}
public void methodTwo(String var) {
lock.readLock().lock;
try {
// Processing
}
finally {
lock.readLock().unlock();
}
}
In this example, methodTwo
can be invoked without blocking as long as the writeLock
on methodOne
has not been locked. This is good and the functionality I'm looking for, however when the writeLock
is locked, it is locked for all cases of var
. Instead, I would like for it only to lock on var
like with synchronized
:
Synchronized Example
public void methodOne(String var) {
synchronized(var) {
// Processing
}
}
public void methodTwo(String var) {
synchronized(var) {
// Processing
}
}
Now, the methods will only block conditional on the input. This is good and and what I'm looking for, however if there are multiple concurrent calls to methodTwo
with the same key, they will block. Instead, I would like this to be a "read" style lock and allow the call.
Essentially, I would like a ReadWriteLock that I can synchronize to a variable to obtain both sets of functionality.
Essentially, I would like a ReadWriteLock that I can synchronize to a variable to obtain both sets of functionality.
First off, depending on the number different values, this might create some huge number of locks. You might consider having some sort of classification or something so you can partition the updates to a small number instead. For example, is there a way you can subdivide the different var values. Maybe there are various types of values? If there is a small fixed number of values then this won't be a problem.
You are going to have to build some sort of collection of ReentrantReadWriteLock
. Maybe use a ConcurrentHashMap
which will store all of the locks.
Map<String, ReadWriteLock> lockMap =
new ConcurrentHashMap<String, ReadWriteLock>():
...
public void writeProcessing(String var) {
lock = lockMap.get(var);
lock.writeLock().lock;
try {
// Processing
} finally {
lock.writeLock().unlock();
}
}
You will need to register the different values beforehand. Or you can create them on demand. Again, this might create some huge number of locks which may be prohibitive.
public void writeProcessing(String var) {
lock = getLockForVar(var);
...
}
private ReadWriteLock getLockForVar(String var) {
ReadWriteLock lock = lockMap.get(var);
if (lock != null) {
return lock;
}
// this might create an extra lock because of race conditions...
lock = new ReadWriteLock();
ReadWriteLock current = lockMap.putIfAbsent(var, lock);
if (current == null) {
return lock;
} else {
return current;
}
}
You could also use some kind of wrapper, if feasible. So will have a unique lock for each wrapped object.
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public abstract class ThreadSafeWrapper<T> {
private final ReadWriteLock lock = new ReentrantReadWriteLock();
private final T object;
public ThreadSafeWrapper(T object) {
this.object = object;
}
public final void methodOneWriteLock(String var) {
lock.writeLock().lock();
try {
doMethodOne(object, var);
} finally {
lock.writeLock().unlock();
}
}
public final void methodTwoReadLock(String var) {
lock.readLock().lock();
try {
doMethodTwo(object, var);
} finally {
lock.readLock().unlock();
}
}
protected abstract void doMethodOne(T obj, String var);
protected abstract void doMethodTwo(T obj, String var);
}
Could be used like that:
public class SampleWrapper {
public static void main(String[] args) {
ThreadSafeWrapper<String> wrapper = new ThreadSafeWrapper<String>("lala") {
@Override
protected void doMethodOne(String obj, String var) {
System.out.println("method one: " + obj + " " + var);
}
@Override
protected void doMethodTwo(String obj, String var) {
System.out.println("method two: " + obj + " " + var);
}
};
wrapper.methodOneWriteLock("foo");
wrapper.methodTwoReadLock("bar");
}
}
You could do something similar with interfaces. Its just to point you in some direction.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With