2009-12-03 70 views
0

我有一個類的管理器,將被多個線程同時訪問,我想知道我是否以正確的方式做到了這一點?
還我想我需要RemoveFoo是原子,但我不知道java線程安全代碼+原子方法問題

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 
{} 
+0

我不知道Java,但在C#中成規鎖同步的一些私人的事情,所以這是不是最好的挑... – Peter

+0

其實,它不併使它所以將減緩進入的Foo下來。 @Aaron指出,你確實需要檢查foo上的空值。 – Robin

回答

3

RemoveFoo可能有問題。我建議使用:

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

改爲。這確保地圖在get()remove()之間不會改變。

Foo,這足以對bars,而不是整個實例同步。但這只是一個小小的優化。

+0

非常好的主意,在刪除foo之前removeAll :) – Omu

+1

+1這更加簡潔,雖然唯一真正需要的是檢查null。即使該項目已被刪除,刪除仍然可以正常工作。 – Robin

1

聲明RemoveFoo(String)爲​​:

public synchronized void RemoveFoo(String name) { 
    … 
} 

同時,告知如下:

  • 方法名稱應該是小寫,例如removeFoo而不是RemoveFoo。這不是C#。 :)
  • 每種方法都需要返回類型:public removeFoo()不是有效的方法聲明,它需要是public void removeFoo()
+0

:D是的,這肯定不是C# – Omu

+0

如果我將它聲明爲synchronized,其他線程是否可以同時使用此方法? – Omu

+1

對。一個'synchronized'方法一次只能由一個線程執行。 – Bombe

4

因爲您正在使用ConcurrentHashMap,所以不需要同步方法,但請注意Foo foo = foos.Get(name)可能會返回null,因爲另一個線程可能已經從地圖中刪除了該條目。

成員可以聲明爲Map<String, Foo> foos,但如果你在美孚使用的ConcurrentHashMap像

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

也許你可以在富同步廢除以及必須initialsed爲foos = new ConcurrentHashMap<String, Foo>;

1

我不確定你要在Foo和Bar上做什麼,但它看起來像是一種釋放模式。

如果他們沒有被別人引用,只需調用foos.Remove(name);並讓GC引擎處理重新分配。

+0

我有一些邏輯(去DB)做每個酒吧之前,它從地圖中刪除 – Omu