Как правильно создать класс SynchronizedStack? - PullRequest
7 голосов
/ 02 февраля 2011

Я сделал простой синхронизированный объект стека в Java, просто для учебных целей. Вот что я сделал:

public class SynchronizedStack {
    private ArrayDeque<Integer> stack;

    public SynchronizedStack(){
        this.stack = new ArrayDeque<Integer>();     
    }

    public synchronized Integer pop(){
        return this.stack.pop();
    }

    public synchronized int forcePop(){
        while(isEmpty()){
            System.out.println("    Stack is empty");
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return this.stack.pop();
    }

    public synchronized void push(int i){
        this.stack.push(i);
        notifyAll();
    }

    public boolean isEmpty(){
        return this.stack.isEmpty();
    }

    public synchronized void pushAll(int[] d){
        for(int i = 0; i < d.length; i++){
            this.stack.push(i);
        }
        notifyAll();
    }

    public synchronized String toString(){
        String s = "[";
        Iterator<Integer> it = this.stack.iterator();   
        while(it.hasNext()){
            s += it.next() + ", ";
        }
        s += "]";
        return s;
    }
}

Вот мои вопросы:

  • Можно ли не синхронизировать метод isEmtpy()? Я подумал, что это потому, что даже если другой поток изменяет стек одновременно, он все равно будет возвращать согласованный результат (нет операции, которая переходит в состояние isEmpty, которое не является ни начальным, ни конечным). Или лучше разработать синхронизацию всех методов синхронизированного объекта?

  • Мне не нравится метод forcePop(). Я просто хотел создать поток, который мог бы ждать, пока элемент не будет помещен в стек, прежде чем извлекать элемент, и я подумал, что лучше всего сделать цикл с wait() в методе run() потока , но я не могу, потому что это бросает IllegalMonitorStatException. Как правильно сделать что-то подобное?

  • Любой другой комментарий / предложение?

Спасибо!

Ответы [ 4 ]

9 голосов
/ 02 февраля 2011
  • Stack сам уже синхронизирован, поэтому нет смысла снова применять синхронизацию (используйте ArrayDeque, если вы хотите использовать несинхронизированный стек)

  • Это НЕ ОК (кроме факта из предыдущего пункта), потому что отсутствие синхронизации может вызвать эффект видимости памяти.

  • forcePop() довольно хорошо. Хотя он должен пройти InterruptedException, не ловя его, чтобы следовать контракту метода прерываемой блокировки. Это позволит вам прервать поток, заблокированный на forcePop() вызове, вызвав Thread.interrupt().

0 голосов
/ 02 февраля 2011

Я думаю, вы немного смешиваете идиомы.Вы поддерживаете SynchronizedStack с java.util.Stack, что в свою очередь поддерживается java.util.Vector, что составляет synchronized.Я думаю, вы должны инкапсулировать поведение wait() и notify() в другом классе.

0 голосов
/ 02 февраля 2011

Предположим, что stack.isEmpty() не потребуется синхронизация, может быть правдой, но вы полагаетесь на детали реализации класса, который не контролируется. В Javadocs Stack говорится, что класс не является потокобезопасным, поэтому вам следует синхронизировать весь доступ.

0 голосов
/ 02 февраля 2011

Единственная проблема с не синхронизацией isEmpty() заключается в том, что вы не знаете, что происходит внизу. Хотя ваши рассуждения вполне разумны, они предполагают, что базовый Stack также ведет себя разумно. Что, вероятно, и есть в данном случае, но вы не можете полагаться на это в целом.

И вторая часть вашего вопроса, нет ничего плохого в операции блокирования всплывающих окон, см. this для полной реализации всех возможных стратегий.

И еще одно предложение: если вы создаете класс, который может быть повторно использован в нескольких частях приложения (или даже в нескольких приложениях), не используйте методы synchronized. Сделайте это вместо:

public class Whatever {
  private Object lock = new Object();

  public void doSomething() {
    synchronized( lock ) {
      ...
    }
  }
}

Причина этого в том, что вы на самом деле не знаете, хотят ли пользователи вашего класса синхронизироваться с вашими Whatever экземплярами или нет. Если они это сделают, они могут помешать работе самого класса. Таким образом, вы получите свой собственный личный замок, которому никто не сможет помешать.

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