我有一个应用程序可以创建一些对象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);
}
}
}
}
答案 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。只需记住将密钥传递给相应的构造函数。