2012-01-10 76 views
2

我最近有a problem with two threads sticking in deadlock because they weren't monitoring the same object the way I thought they were。事實證明,實施Singleton模式solved the problem但是爲什麼?爲什麼我需要這個多線程應用程序中的Singleton模式?

我只實例化了其中一個對象是私有屬性的類的一個實例,所以我期望它實際上是單實例。


對於這個問題的完整起見,在這裏也說明差異的一些代碼:

Singleton模式開始實施前:

class Worker { 
    private BlockingQueue q = new LinkedBlockingQueue(); 

    public void consume(String s) { 
     // Called by thread 1. 
     // Waits until there is anything in the queue, then consumes it 
    } 

    public void produce(String s) { 
     // Called by thread 2. 
     // Puts an object in the queue. 
    } 

    // Actually implements Runnable, so there's a run() method here too... 
} 

細絲卻開始是這樣的:

Worker w = new Worker(); 
new Thread(w).start(); 

// Producer also implements Runnable. It calls produce on its worker. 
Producer p = new Producer(w); 
new Thread(p).start(); 

現在,當我檢查實際上是隊列用於produce()consume(),System.identityHashCode(q)在不同的線程中給出了不同的結果。

隨着Singleton模式:

class Worker { 
    private static BlockingQueue q; 
    private BlockingQueue getQueue() { 
     if(q == null) { 
      q = new LinkedBlockingQueue(); 
     } 
     return q; 
    } 
    // The rest is unchanged... 
} 

突然,它的工作原理。爲什麼這裏需要這種模式?

+1

由於這不是可編譯的代碼,因此很難確定您的實際實施中可能發生了什麼。 – Perception 2012-01-10 21:56:17

+2

你在這裏顯示的任何東西都不會產生你描述的情況。 – 2012-01-10 21:58:19

+0

他在這裏發佈了服務器和工作者代碼:http://pastebin.com/VZLUH2DT當然,在這裏發佈的線程啓動代碼也有幫助。 – jbindel 2012-01-10 22:01:13

回答

4

問題是,您在Server構造函數內部創建了一個new Worker()。你有這樣的:

public Server(Worker worker) { 
    this.clients = new ArrayList<ClientHandle>(); 
    this.worker = new Worker(); // This is the problem. 


// Don't do this in the Server constructor. 
this.worker = new Worker(); 

// Instead do this: 
this.worker = worker; 
+0

既然你不需要在這裏使用Singleton模式,我也會避免它。 – jbindel 2012-01-10 22:01:59

2

根據您所張貼的僞代碼,它實際上並沒有那麼做的差的單例模式,而只是使用static。在你的第一個例子中,隊列沒有被聲明爲靜態的,因此每個Worker的實例都要實例化它自己的LinkedBlockingQueue。當您在第二個示例中聲明static時,隊列將在類級別創建並在所有實例之間共享。

根據您在您的其他問題發佈的代碼,錯誤就在這裏的最後一行:

public Server(Worker worker) { 
     this.clients = new ArrayList<ClientHandle>(); 
     this.worker = new Worker(); 

所以,你的發言

我只實例化的類的一個實例其中對象是 的私人財產,所以我預計它是有效的單身人士 無論如何。

是不準確的。您正在每個新服務器上爲新工作人員提供數據,而不是重新使用傳入的服務器。

相關問題