如何正确创建SynchronizedStack类?
我用 Java 制作了一个简单的同步 Stack 对象,仅用于培训目的。 这是我所做的:
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()
中的wait()
进行循环线程的run()
方法,但我不能,因为它会抛出IllegalMonitorStatException
。执行此类操作的正确方法是什么?还有其他评论/建议吗?
谢谢你!
I made a simple synchronized Stack object in Java, just for training purposes.
Here is what I did:
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;
}
}
Here are my questions:
Is it OK not to synchronize the
isEmtpy()
method? I figured it was because even if another Thread is modifying the stack at the same time, it would still return a coherent result (there is no operation that goes into a isEmpty state that is neither initial or final). Or is it a better design to have all the methods of a synchronized object synchronized?I don't like the
forcePop()
method. I just wanted to create a thread that was able to wait until an item was pushed into the stack before poping an element, and I thought the best option was to do the loop with thewait()
in therun()
method of the thread, but I can't because it throws anIllegalMonitorStatException
. What is the proper method to do something like this?Any other comment/suggestion?
Thank you!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
Stack
本身已经同步,因此再次应用同步是没有意义的(如果您想要非同步堆栈实现,请使用ArrayDeque
)这不是好的(除了上一点的事实),因为缺乏同步可能会导致内存可见性影响。
forcePop()
非常好。尽管它应该传递 InterruptedException 而不捕获它,以遵循可中断阻塞方法的约定。它允许您通过调用Thread.interrupt()
来中断在forcePop()
调用中阻塞的线程。Stack
itself is already synchronized, so it doesn't make sense to apply synchronization again (useArrayDeque
if you want a non-synchronized stack implementation)It's NOT OK (aside from the fact from the previous point), because lack of synchronization may cause memory visibility effects.
forcePop()
is pretty good. Though it should passInterruptedException
without catching it to follow the contract of interruptable blocking method. It would allow you to interrupt a thread blocked atforcePop()
call by callingThread.interrupt()
.假设 stack.isEmpty() 不需要同步可能是正确的,但您依赖于您无法控制的类的实现细节。
Stack 的 javadoc 声明该类不是线程安全的,因此您应该同步所有访问。
Assuming that
stack.isEmpty()
won't need synchronization might be true, but you are relying on an implementation detail of a class that you have no control over.The javadocs of Stack state that the class is not thread-safe, so you should synchronize all access.
我认为你有点混合了习语。您使用
java.util.Stack
支持您的SynchronizedStack
,而java.util.Stack
又由java.util.Vector
支持,即同步
。我认为您应该将wait()
和notify()
行为封装在另一个类中。I think you're mixing idioms a little. You are backing your
SynchronizedStack
withjava.util.Stack
, which in turn is backed byjava.util.Vector
, which issynchronized
. I think you should encapsulate thewait()
andnotify()
behaivor in another class.不同步 isEmpty() 的唯一问题是您不知道下面发生了什么。虽然您的推理是合理的,但它假设底层 Stack 也以合理的方式运行。在本例中可能就是这样,但一般情况下您不能依赖它。
您问题的第二部分,阻塞弹出操作没有任何问题,请参阅 this 用于完整实施所有可能的策略。
还有一个建议:如果您要创建一个可能在应用程序的多个部分(甚至多个应用程序)中重复使用的类,请不要使用
同步
方法。这样做:这样做的原因是您并不真正知道您的类的用户是否想要在您的
Whatever
实例上同步。如果他们这样做,他们可能会干扰班级本身的运作。这样您就拥有了自己的私人锁,任何人都无法干预。The only problem with not synchronizing
isEmpty()
is that you don't know what's happening underneath. While your reasoning is, well, reasonable, it assumes that the underlyingStack
is also behaving in a reasonable manner. Which it probably is in this case, but you can't rely on it in general.And the second part of your question, there's nothing wrong with a blocking pop operation, see this for a complete implementation of all the possible strategies.
And one other suggestion: if you're creating a class that is likely to be re-used in several parts of an application (or even several applications), don't use
synchronized
methods. Do this instead:The reason for this is that you don't really know if users of your class want to synchronize on your
Whatever
instances or not. If they do, they might interfere with the operation of the class itself. This way you've got your very own private lock which nobody can interfere with.