0

我有一个将被多个线程同时访问的类管理器,我想知道我这样做是否正确?
我也认为我需要 RemoveFoo 是原子的,但我不确定

public class Manager
{
    private ConcurrentHashMap<String, Foo> foos;
    //init in constructor

    public RemoveFoo(String name)
    {
        Foo foo = foos.Get(name);
        foo.RemoveAll();
        foos.Remove(name);
    }

    public AddFoo(Foo foo)
    {...}
}

public class Foo
{
    private Map<String,Bar> bars;
    //intialize it in constructor

    //same for RemoveBar
    public void AddBar(Bar bar)
    {
        synchronized(this)
        {
            bars.put(bar.id, bar);
        }
    }

    public void RemoveAll()
    {
        synchronized(this)
        {
            //some before removall logic for each one
            bars.remove(bar.id, bar);
        }
    }

}

public class Bar
{}
4

5 回答 5

4

您不需要同步方法,因为您使用的是 ConcurrentHashMap,但请注意,它Foo foo = foos.Get(name)可能会返回 null,因为另一个线程可能已经从映射中删除了该条目。

成员可以声明为Map<String, Foo> foos,但必须首字母为foos = new ConcurrentHashMap<String, Foo>;

于 2009-12-03T09:15:43.183 回答
3

RemoveFoo可能有问题。我建议使用:

Foo foo = foos.remove (name);
if (foo != null) foo.removeAll();

反而。这确保地图不会在get()和之间变化remove()

在中,同步而不是整个实例Foo就足够了。bars但这只是一个小的优化。

于 2009-12-03T09:08:02.443 回答
1

声明RemoveFoo(String)synchronized

public synchronized void RemoveFoo(String name) {
    …
}

此外,请注意以下事项:

  • 方法名称应该是小写的,例如,removeFoo而不是RemoveFoo. 这不是 C#。:)
  • 每个方法都需要一个返回类型:public removeFoo()不是一个有效的方法声明,它必须是public void removeFoo().
于 2009-12-03T09:07:20.307 回答
1

如果您在 Foo 中使用 concurrentHashMap

private Map<String,Bar> bars = new ConcurrentHashMap<String, Bar>();

也许您也可以取消 Foo 中的同步。

于 2009-12-03T19:58:06.137 回答
1

我不确定你要在 Foo 和 Bar 上做什么,但它看起来像是一种释放模式。

如果他们没有被其他人引用,只需调用 foos.Remove(name); 并让 GC 引擎处理释放。

于 2009-12-04T16:52:08.313 回答