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

发布于 2024-11-26 22:59:29 字数 1461 浏览 1 评论 0原文

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

对象 Foo 包含 2 个队列(b_queue 和 c_queue),一个队列填充 B 类型的对象,另一个填充 C 类型的对象。

有一个对象层次结构,其中 B 或 C 中发生某些事件,我希望它们将自己从对象 Foo 的队列中删除。

我的解决方案是构造一个对象 B 或 C,将 Foo 的实例(称为 foo_inst)交给它们,该实例将把它们存储在队列中。 然后在B或CI内部就可以调用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);
        }
    }
}

}

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

}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

待天淡蓝洁白时 2024-12-03 22:59:29

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

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

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

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);
}
掩耳倾听 2024-12-03 22:59:29

为什么不直接使用 HashSets- 这样,您可以将 B 和 C 实例存储在 2 个单独的哈希集中。实际上,您甚至可以通过声明 HashSet对 B 和 C 对象使用 1 个哈希集。 bnc = HashSet()。现在,如果您想删除特定实例,只需使用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。只需记住将密钥传递给相应的构造函数即可。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文