开发者

Java: Concurrently removing objects from queues.

开发者 https://www.devze.com 2023-03-24 06:32 出处:网络
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 typ

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消