gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-30 06:15:43 25 4
gpt4 key购买 nike

我有一个 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崩溃?

最佳答案

Has some multithread problems cause Stack crash?

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

您的代码缺少一个小但关键的更改。

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

这里的if子句应该是一个while循环。正如 @Ivan 指出的,如果您的架构遭受虚假唤醒,这很重要,但这也修复了更可能的竞争条件。

如果您有多个线程从堆栈中消耗数据,则可能有 2 个线程等待 pop(),其中线程 A 位于 synchronized block 和线程的开头-B 在 wait() 处。当另一个线程执行 push()notify() 时,等待线程 B 将从等待队列移动到阻塞队列,但它会在已经被阻塞的线程A后面。当执行推送的线程释放锁时,线程 A 首先获取锁,然后从列表中获取对象并解锁。然后线程 B 继续前进并调用 removeLast(),但堆栈中没有项目,并抛出 NoSuchElementException

// we use while here to protect against the race condition
while (list.size() <= 0) {
wait();
}
return list.removeLast();

通过使用 while,一旦线程 A 获得锁,它就可以重新检查以确保另一个线程没有从它收到通知的堆栈中“窃取”项目。有关此竞争条件的更多详细信息,请参阅我的 old page on this topic here

其他一些评论:

  • 您不需要在列表同时使用synchronized方法和synchronized block 。我建议删除方法上的 synchronized 关键字,除非有其他代码您没有向我们展示,而只是在 列表 上同步。然后你应该执行list.wait()
  • list 字段应为 privatefinal,如果您是synchronized,则建议在线程程序中使用这两种方式就在上面。

关于java - 这个Stack类有一些多线程问题吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49247898/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com