Как правильно создать класс SynchronizedStack?

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

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 ответов


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

  • это не нормально (помимо факта с предыдущей точки), потому что отсутствие синхронизации может вызвать эффекты видимости памяти.

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


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


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


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

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

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

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

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

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