2012-01-10 64 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(); 

所以,你的发言

我只实例化的类的一个实例其中对象是 的私人财产,所以我预计它是有效的单身人士 无论如何。

是不准确的。您正在每个新服务器上为新工作人员提供数据,而不是重新使用传入的服务器。

相关问题