这个Stack类有一些多线程问题吗?

时间:2018-03-13 03:34:56

标签: java multithreading

我有一个Stack类,就像这样

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();
        }
    }
}

当多线程访问Stack类时,是否有一些多线程问题导致Stack崩溃?

1 个答案:

答案 0 :(得分:1)

  

是否有一些多线程问题导致堆栈崩溃?

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

您的代码缺少一个小而重要的变化。

synchronized (list) {
    // here's your problem, if should be while
    if (list.size() <= 0) {
        wait();
    }
    return list.removeLast();
}

这里的if子句应该是while循环。正如@Ivan指出的那样,如果您的架构受到虚假唤醒的影响,这一点很重要,但这也可以解决更可能的竞争条件。

如果您的堆栈中有多个线程消耗,则可能有2个线程等待pop()synchronized块开头的线程A和{{1}的线程B }。当另一个线程执行wait()push()时,等待的线程B将从等待队列移动到被阻塞的队列,但它将隐藏在线程A之后已被封锁。当执行推送的线程释放锁定时,线程A首先获得锁定并从列表中获取对象并解锁。然后线程B继续前进并调用notify(),但堆栈中没有任何项目,它会抛出removeLast()

NoSuchElementException

通过使用// we use while here to protect against the race condition while (list.size() <= 0) { wait(); } return list.removeLast(); ,一旦线程A获得锁定,它就可以重新检查以确保另一个线程没有从被通知的堆栈中“窃取”该项目。有关此种族情况的详细信息,请参阅我的old page on this topic here

结合其他评论:

  • while上不需要 synchronized方法和synchronized块。我建议您只删除方法上的list关键字,除非您没有向我们展示其他代码,只需在synchronized上同步。然后,您应该list
  • list.wait()字段应为listprivate,如果您final上有synchronized,则建议使用这些字段。
相关问题