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