Java 这个堆栈类有一些多线程问题?

Java 这个堆栈类有一些多线程问题?,java,multithreading,Java,Multithreading,我有一个堆栈类,像这样 public class Stack { LinkedList list = new LinkedList(); public synchronized void push(Object x) { synchronized (list) { list.addLast(x); notify(); } } public synchronized Object

我有一个堆栈类,像这样

public class Stack {

    LinkedList list = new LinkedList();

    public synchronized void push(Object x) {
        synchronized (list) {
            list.addLast(x);
            notify();
        }
    }

    public synchronized Object pop () throws Exception {
        synchronized (list) {
            if (list.size() <= 0) {
                wait();
            }
            return list.removeLast();
        }
    }
}
公共类堆栈{
LinkedList=新建LinkedList();
公共同步无效推送(对象x){
已同步(列表){
列表。addLast(x);
通知();
}
}
公共同步对象pop()引发异常{
已同步(列表){
if(list.size()
是否有一些多线程问题导致堆栈崩溃

将来,您应该始终提供异常详细信息,以便我们能够更好地或至少定义“崩溃”的含义,并提供日志输出。在这种情况下,我怀疑您得到了一个
NoTouchElementException

// we use while here to protect against the race condition
while (list.size() <= 0) {
    wait();
}
return list.removeLast();
您的代码缺少一个小但关键的更改

synchronized (list) {
    // here's your problem, if should be while
    if (list.size() <= 0) {
        wait();
    }
    return list.removeLast();
}
通过使用
while
,一旦thread-A获得锁,它就可以重新检查以确保另一个线程没有从堆栈中“窃取”通知它的项。有关此争用条件的更多详细信息,请参阅my

其他几点意见:

  • 您不需要
    同步
    方法和
    列表
    上的
    同步
    块。我建议只删除方法上的
    同步
    关键字,除非您没有显示其他代码,只需在
    列表
    上同步。然后您应该执行
    列表。等待()
  • 列表
    字段应该是
    private
    final
    ,如果线程程序中的
    已同步
    ,则建议使用这两个字段

错误是什么?为什么要在两个对象上同步两次?您最好执行以下操作:将
列表设置为私有,并删除内部
已同步的
块。此外,最好将
通知()
替换为
notifyAll()
并在一个周期内调用
等待()
,以避免与以下内容相关的错误唤醒: