为什么在这个多线程应用程序中需要Singleton模式?

时间:2012-01-10 21:48:44

标签: java multithreading singleton

我最近有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模式之前:

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)在不同的线程中给出了不同的结果。

使用单身人士模式:

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

突然间,它有效。为什么这种模式在这里是必要的?

2 个答案:

答案 0 :(得分:4)

问题是您在new Worker()构造函数中创建了Server。你有这个:

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;

答案 1 :(得分:2)

根据您发布的伪代码,实际上并不是单例模式产生差异,而只是使用static。在第一个示例中,队列未声明为静态,因此Worker的每个实例都将实例化其自己的LinkedBlockingQueue个实例。在第二个示例中声明static时,队列级别创建并在所有实例之间共享。

根据您在其他问题中发布的代码,错误就在最后一行:

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

所以你的陈述

  

我只实例化了该对象所在类的一个实例   一个私有财产,所以我期望它有效地成为单身人士   反正。

不准确。你是在每个新服务器中实现一个新的工作者,而不是重用传入的服务器。