Assume that we have a method doSomething(String input)
and we want to run it synchronized by different inputs.
It means that running doSomething(A)
should block any consecutive calls of doSomething(A)
until the first one is completed BUT should not block doSomething(B)
or doSomething(C)
.
So i've created a wrapper method to achieve this goal. It creates objects based on input value and places locks on them and keeps a reference to them in a list.
private static final ArrayList<String> runningTasks = new ArrayList<>();
public void doSomethingSyncedByInput(String input) {
// Create a lock or load an already created lock from the list.
// (Yeah, it's a race condition but forget about it. It's just an example.)
String lock = new String(input);
if(runningTasks.contains(input)){
// get currently available lock object
lock = runningTasks.get(runningTasks.indexOf(input));
}else {
// add a reference on tasks list
runningTasks.add(lock);
}
synchronized (lock) {
doSomething(input);
}
}
It actually works; but it's not a totally thread-safe solution as ArrayList
is not thread-safe. The contents of ArrayList
is not volatile and according to documentation, adding and removing items on the list is not reflected on other threads instantly.
Note that this implementation is not synchronized. If multiple threads access an
ArrayList
instance concurrently, and at least one of the threads modifies the list structurally, it must be synchronized externally.
A well known thread safe variant of ArrayList
is CopyOnWriteArrayList
(which makes a copy of the elements and re-sets the inner volatile
field holding elements to be sure to have latest version of the list on all other threads instantly). As the name yields, it COPIES each one of the list items on adding a new item to the list and it means the references to the actual objects that got the lock on, would be lost and the code will be broken.
So I need a datatype which holds a list of objects and doesn't copy or change objects in favor of concurrency support. I could use String.intern()
functionality but it brings a lot of potential problems especially on mobile platforms.
Any ideas?
Or, do you know any bulletproof implementations available to use?
I'm on Android platform by the way.
UPDATE:
I've reached a solution by myself. Check out my own answer. Comments are welcomed.