I have below class structures in my project for class A and class B:
class A {
private String id;
private List<B> bs = new ArrayList<B>();
A(String id){
this.id = id;
}
public List<B> getBs(){
return bs;
}
public void setBs(List<B> bs){
this.bs=bs;
}
public void addBs(List<B> bs){
this.bs.addAll(bs);
}
public void addB(B b){
this.bs.add(b);
}
}
class B {
private String id;
private List<String> tags;
B(String id){
this.id = id;
}
public List<String> getTags(){
return tags;
}
public void setTags(List<String> tags){
this.tags = tags;
}
public void addTags(List<String> tags){
this.tags.addAll(tags);
}
public void addTag(String tag){
this.tags.add(tag);
}
}
Also we have a cache class:
class CacheService {
private static final ConcurrentHashMap<String, Object> CACHE = new ConcurrentHashMap<String, Object>();
public static Object get(String id){
return CACHE.get(id);
}
public static void put(String id, Object obj){
return CACHE.put(id, obj);
}
}
Now objects for class A and B are created using unique IDs and put in this cache by <id, object> combination. For example:
A a1 = new A("10");
CacheService.put("10", a1);
A a2 = new A("11");
CacheService.put("11", a2);
B b1 = new B("1");
CacheService.put("1", b1);
B b2 = new B("2");
CacheService.put("2", b2);
B b3 = new B("3");
CacheService.put("3", b3);
B b4 = new B("4");
CacheService.put("4", b4);
Also I am putting class B objects in the List<B> inside objects a1 and a2. It is important to note that a unique B object is only put once in any A object:
a1.add(b1);
a1.add(b2);
a2.add(b3);
a2.add(b4);
This way we can have multiple objects for class A and B in the CACHE.
Scenario: Now multiple threads access this CACHE but some of them end up to get class A objects and others class B objects depending upon ID specified by user. These threads actually want to read or update information on these objects.
Question: My requirement is when a thread has accessed an object of class A (for example a1) to update it then no other thread should be able to read or update a1 as well as all class B objects (b1 and b2 in this case) which are added to the List<B> inside object a1 until I am finished with all updates on a1. Please tell me how can I acquire a lock in this scenario?
EDIT2: I was going to complete my answer after question was edited, but I just found the class java.util.concurrent.locks.ReentrantReadWriteLock, which I think fits exactly the needs of user sohanlal.
This class provides a pair of locks, one for reading operations that can be owned at the same time by several elements and is not-blocking by itself. The second one (the write part) avoids any read or write operation when acquired.
The solution is then as following:
Code. This has not been tested, but will give an idea of how it should be implemented:
ORIGINAL ANSWER:
Jeff’s answer is a good starting point, since it appears to solve the problem of touching the A-type object, and modifying its composition. However, we still have a problem related with theB-type objects contained on A.
Suppose we have an A-type object with several B-type elements inside:
The thing is that, if you are operating over
a1, you want to lock any operation overb1,b2andb3. How can you make sure of that?The only solution I see is that all the B elements inside an A container share some common Lock variable. At the time of invoking write-related operations over
a1, it acquires the lock, avoiding ANY operation over B elements. Note that no operation over a B element needs to actually acquire the lock… only to check if it has been acquired by A-type container.A lot of drawbacks/considerations:
a1, you have to provide B with the shared lock. When extracted, the lock must be dereferenced. What happens if container A is deleted? You have to take care of that kind of things.EDIT: and I forgot to mention that this mechanism, when writing the A-type container, does not “stop” or take into account ongoing operations over the contained B-type elements.