Зачем мне нужен шаблон Singleton в этом многопоточном приложении? - PullRequest
2 голосов
/ 11 января 2012

У меня недавно была проблема с двумя потоками, зависшими в тупике, потому что они не контролировали один и тот же объект, как я думал, что они были . Как оказалось, реализация шаблона 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) дал разные результаты в разных потоках.

С одиночным рисунком:

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

Вдруг это работает. Почему этот шаблон необходим здесь?

Ответы [ 2 ]

4 голосов
/ 11 января 2012

Проблема в том, что вы создаете 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;
2 голосов
/ 11 января 2012

Основываясь на опубликованном вами псевдокоде, на самом деле это не шаблон синглтона, а просто использование static. В вашем первом примере очередь не объявлена ​​как статическая, поэтому каждый экземпляр Worker создается в своем экземпляре LinkedBlockingQueue. Когда вы объявляете это static во втором примере, очередь создается на уровне класса и распределяется между всеми экземплярами.

Исходя из кода, который вы разместили в своем другом вопросе, ошибка находится здесь, в последней строке:

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

Итак, ваше заявление

Я создал только один экземпляр класса, объектом которого был частная собственность, поэтому я ожидал, что она будет фактически единой в любом случае.

неточно. Вы очищаете нового работника на каждом новом сервере, а не повторно используете тот, который был передан.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...