Java 如何正确创建SynchronizedStack类?

Java 如何正确创建SynchronizedStack类?,java,multithreading,synchronization,Java,Multithreading,Synchronization,我用Java制作了一个简单的同步堆栈对象,只是为了进行培训。 以下是我所做的: public class SynchronizedStack { private ArrayDeque<Integer> stack; public SynchronizedStack(){ this.stack = new ArrayDeque<Integer>(); } public synchronized Integer p

我用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;
    }
}
公共类SynchronizedStack{
专用ArrayDeque堆栈;
公共同步堆栈(){
this.stack=new ArrayDeque();
}
公共同步整数pop(){
返回这个.stack.pop();
}
public-synchronized int-forcePop(){
while(isEmpty()){
System.out.println(“堆栈为空”);
试一试{
等待();
}捕捉(中断异常e){
e、 printStackTrace();
}
}
返回这个.stack.pop();
}
公共同步无效推送(int i){
这个.栈.推(i);
notifyAll();
}
公共布尔值为空(){
返回此.stack.isEmpty();
}
公共同步void pushAll(int[]d){
对于(int i=0;i
以下是我的问题:

  • 不同步
    isEmtpy()
    方法可以吗?我认为这是因为即使另一个线程同时修改堆栈,它仍然会返回一致的结果(没有任何操作进入非初始或最终的等空状态)。或者让同步对象的所有方法都同步是更好的设计

  • 我不喜欢
    forcePop()
    方法。我只是想创建一个线程,在弹出一个元素之前可以等到一个项目被推入堆栈,我认为最好的选择是使用线程的
    run()
    方法中的
    wait()
    进行循环,但我不能,因为它抛出了一个
    illegalMonitorStateException
    。这样做的正确方法是什么

  • 还有其他意见/建议吗


谢谢大家!

不同步的唯一问题是不知道下面发生了什么。虽然您的推理是合理的,但它假定底层的
堆栈
也以合理的方式运行。在这种情况下很可能是这样,但一般来说你不能依赖它

问题的第二部分,阻塞pop操作没有错,请参阅所有可能策略的完整实现

还有一个建议:如果您创建的类可能会在应用程序的多个部分(甚至多个应用程序)中重复使用,请不要使用
synchronized
方法。改为这样做:

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

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

原因是您不知道类的用户是否希望在
实例上同步。如果这样做,它们可能会干扰类本身的操作。这样,您就拥有了自己的私有锁,没有人可以干预。

假设
stack.isEmpty()
不需要同步可能是真的,但您依赖于您无法控制的类的实现细节。 堆栈的javadocs声明该类不是线程安全的,因此您应该同步所有访问。

  • Stack
    本身已经同步,因此再次应用同步是没有意义的(如果需要非同步的Stack实现,请使用
    ArrayDeque

  • 这是不正常的(除了上一点之外),因为缺少同步可能会导致内存可见性影响

  • forcePop()
    相当不错。虽然它应该通过
    InterruptedException
    而不捕获它,以遵循可中断阻塞方法的契约。它允许您通过调用
    thread.interrupt()
    来中断在
    forcePop()调用中阻塞的线程


    • 我觉得你把习语混在一起了。您正在使用
      java.util.Stack
      支持您的
      SynchronizedStack
      ,而
      java.util.Vector
      又支持
      synchronized
      。我认为应该将
      wait()
      notify()
      行为封装在另一个类中。

      不要锁定方法,而是锁定对象。阅读以下内容:堆栈扩展向量,该向量已同步。Don Roby:是的,正如axtavt所指出的,我现在使用的是ArrayDeque。Sean Patrick Floyd:所以你说这样做更好:public void pop(){synchronized(this.stack){return this.stack.pop();}}而不是public void synchronized pop(){return this.stack.pop();}?假设我在不依赖Stack/ArrayQue实现的情况下编写了此代码,但仅以我确信不存在可能导致不一致isEmpty()结果的传递状态的方式使用数组。最好不要同步它(更快)还是同步它(更安全)?无论如何同步它-问题是,如果没有一些同步,您可能-永远不会-在isEmpty()调用中看到来自另一个线程的更新。