【问题标题】:Why do I need the Singleton pattern in this multithreaded application?为什么在这个多线程应用程序中需要单例模式?
【发布时间】:2012-01-10 21:48:44
【问题描述】:

我最近有a problem with two threads sticking in deadlock because they weren't monitoring the same object the way I thought they were。事实证明,实现了单例模式solved the problem但是为什么呢?

我只实例化了一个对象是私有属性的类的实例,所以我希望它无论如何都是有效的单例。


为了问题的完整性,这里还有一些说明差异的代码:

在实现单例模式之前:

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...
}

突然间,它起作用了。为什么这里需要这种模式?

【问题讨论】:

  • 鉴于这是不可编译的代码,因此很难确定您的实际实现中可能发生了什么。
  • 您在此处显示的任何内容都不会产生您所描述的情况。
  • 他在这里发布了 Server 和 Worker 代码:pastebin.com/VZLUH2DT 当然,这里发布的线程启动代码也有帮助。
  • 您也不应该使用单例模式(即static 限定符),因为您不能拥有多个工人。如果您尝试使用多个 Worker,那么他们都将使用相同的 queue,这将毫无意义,除非在一些奇怪的人为情况下。 :-)

标签: java multithreading singleton


【解决方案1】:

问题是您在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;

【讨论】:

  • 既然你不需要在这里使用单例模式,我也会避免它。
【解决方案2】:

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

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

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

所以你的陈述

我只实例化了对象所在的类的一个实例 私有财产,所以我希望它实际上是单身人士 无论如何。

不准确。您是在每个新服务器中创建一个新的 Worker,而不是重用传入的那个。

【讨论】:

    猜你喜欢
    • 2016-07-22
    • 1970-01-01
    • 1970-01-01
    • 2010-10-20
    • 1970-01-01
    • 2021-09-21
    • 1970-01-01
    • 2023-03-30
    • 1970-01-01
    相关资源
    最近更新 更多