Java: одновременное удаление объектов из очередей. - PullRequest
0 голосов
/ 31 июля 2011

У меня есть приложение, которое создает сотни экземпляров некоторых объектов 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 ]

2 голосов
/ 31 июля 2011

Мне не нравится привязка классов B и C к Foo с использованием foo_inst.b_queue.remove.Это делает архитектуру слишком тесно связанной.Постарайтесь избежать этого с помощью интерфейсов и других механизмов абстракции.

Вы выявили возможную проблему параллельной валюты.Некоторые блокировки, проверьте перед использованием или другой механизм, чтобы избежать двойного удаления.Возможно

if ( foo_inst.b_queue.contains(this)  )
{
  foo_inst.b_queue.remove(this);
}
1 голос
/ 31 июля 2011

Почему бы вам просто не использовать HashSets - таким образом, вы можете хранить экземпляры B и C в 2 отдельных хэш-наборах.На самом деле, вы даже можете использовать 1 хэш-набор для объектов B и C, объявив HashSet<Object> bnc = HashSet<Object>().Теперь, если вы хотите удалить конкретный экземпляр, просто используйте метод 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 аналогичным образом.Просто не забудьте передать ключ соответствующим конструкторам.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...