Как правильно создать класс 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 случаях или нет. Если они это сделают, они могут помешать работе самого класса. Таким образом, у тебя будет свой собственный замок. которых никто не может помешать.