I have an application that creates hundreds of instances of some objects B and C.
There is an object hierarchy where object Foo contains 2 queues (b_queue and c_queue), one filled with objects of type B and the other with objects of type C.
When some event occurs in B or C, I want them to remove themselves from the queue in object Foo.
My solution is on construction of an object B or C, to hand them the instance of Foo (call it foo_inst) that will be storing them in its queues. Then inside B or C I can just call foo_inst.b_queue.remove(this).
1) Will this be a good/efficient way to do so, or should this be avoided?
Both B and C are Runnable objects, and will be queued with a ThreadPoolExecutor. This means that they may be on the workqueue twice, and might try to call foo_inst.b_queue.remove(this) concurrently, or after it has already been done.
2) Will this pose a problem as well?
Any help or tips much appreciated.
Okay so far I've managed to get this far with some help.(any more help welcome):
public class Foo implements Foo_interface{
ConcurrentHashMap<Key,B> b_map = new ConcurrentHashMap<Key,B>();
ConcurrentHashMap<Key,C> c_map = new ConcurrentHashMap<Key,C>();
public void removeB(Key k){
b_map.remove(k);
}
public void removeC(Key k){
c_map.remove(k);
}
private class B implements Runnable{
Foo foo_inst;
Key key;
public B(Foo foo,Key key){
this.foo=foo;
this.key=key;
}
public void run(){
try{
//some code
}catch(Exception e{
foo.removeB(key);
}
}
}
private class C implements Runnable{
Foo foo_inst;
Key key;
public C(Foo foo,Key key){
this.foo=foo;
this.key = key;
}
publi开发者_StackOverflow社区c void run(){
try{
//some code
}catch(Exception e{
foo.removeC(key);
}
}
}
}
I don't like the tying of classes B and C to Foo by the uses of foo_inst.b_queue.remove. This makes the architecture too tightly coupled. Try to avoid this by interfaces and other abstraction mechanisms.
You have identified a possible cocurrency issue. Some locking, check before use or other mechanism to avoid the double remove. Perhaps
if ( foo_inst.b_queue.contains(this) )
{
foo_inst.b_queue.remove(this);
}
Why don't you just use HashSets- this way, you can store B and C instances in 2 separate hashsets. Actually, you can even use 1 hashset for both B and C objects by declaring HashSet<Object> bnc = HashSet<Object>()
. Now if you want to remove a specific instance, just use the remove(Object o) method. If you want to do this concurrently, the simplest thing would be to synchronize access to your respective hashsets or hashset.
EDIT:
Uh, so I just looked at your solution and here is how you could do this in a thread-safe manner with HashSets.
public class Foo implements Foo_interface{
HashSet<Object> bnc = new HashSet<Object>();
//thread safety using monitors
public synchronized insert(Object o) {
bnc.add(o);
}
public synchronized delete(Object o) {
bnc.remove(o);
}
}
private class B implements Runnable{
Foo f;
public B(Foo f) {
this.f = f;
this.f.insert(this);
}
public void run(){
try{
//some code
}catch(Exception e{
this.f.delete(this);
}
}
}
private class C implements Runnable{
Foo f;
public C(Foo f) {
this.f = f;
this.f.insert(this);
}
public void run(){
try{
//some code
}catch(Exception e{
this.f.delete(this);
}
}
}
If you really want to use keys (which is actually unnecessary in this case), you can always implement a HashMap instead of a HashSet in a similar fashion. Just remember to pass the key to the respective constructors.
精彩评论