Java:同时从队列中删除对象。

时间:2011-07-31 10:09:28

标签: java multithreading blockingqueue

我有一个应用程序可以创建一些对象B和C的数百个实例。

有一个对象层次结构,其中对象Foo包含2个队列(b_queue和c_queue),一个填充了B类对象,另一个填充了C类对象。

当某个事件发生在B或C中时,我希望它们从对象Foo中的队列中删除。

我的解决方案是构建一个对象B或C,将它们的实例Foo(称之为foo_inst)交给它们将它们存储在队列中。 然后在B或C里面我可以调用foo_inst.b_queue.remove(this)。

1)这是一种好的/有效的方法,还是应该避免这种情况?

B和C都是Runnable对象,并将使用ThreadPoolExecutor排队。这意味着它们可能在工作队列中两次,并且可能会尝试同时调用foo_inst.b_queue.remove(this),或者在它已经完成之后调用它。

2)这也会造成问题吗?

非常感谢任何帮助或提示。

好的,到目前为止,我已经设法通过一些帮助得到了这一点。(欢迎任何更多帮助):

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;
    }
    public void run(){
        try{
            //some code
        }catch(Exception e{
            foo.removeC(key);
        }
    }
}

}

2 个答案:

答案 0 :(得分:2)

我不喜欢通过使用foo_inst.b_queue.remove将类B和C绑定到Foo。这使得架构过于紧密耦合。尽量通过接口和其他抽象机制来避免这种情况。

您已发现可能存在的并发问题。一些锁定,使用前检查或其他机制,以避免双重删除。也许

if ( foo_inst.b_queue.contains(this)  )
{
  foo_inst.b_queue.remove(this);
}

答案 1 :(得分:1)

为什么不使用HashSets - 这样,您可以将B和C实例存储在2个单独的哈希集中。实际上,您甚至可以通过声明HashSet<Object> bnc = HashSet<Object>()为B和C对象使用1个哈希集。现在,如果要删除特定实例,只需使用remove(Object o)方法。如果要同时执行此操作,最简单的方法是同步对各自哈希集或哈希集的访问。

修改

呃,所以我只看了你的解决方案,以下是如何使用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);
        }
    }
}

如果你真的想使用键(在这种情况下实际上是不必要的),你总是可以以类似的方式实现HashMap而不是HashSet。只需记住将密钥传递给相应的构造函数。