0

我有这部分的课程

private static Stack<Integer> integers = new Stack<Integer>();

private static int nextInt()
{               
    if(integers.isEmpty())
    {
        refill();
    }

    return integers.pop();
}

public static int peekInt()
{
    if(integers.isEmpty())
    {
        refill();
    }

    return integers.peek();
}

private static synchronized void refill()
{
    for(int i = 0; i<7; i++)
        integers.add(i);
    Collections.shuffle(integers);
}

并且两个不同的线程调用方法 nextInt 和 peekInt 但有时它们会得到一个堆栈空异常但是如果它们都在获取它们的值之前调用 refill 为什么会发生这种情况。

这是异常跟踪

Exception in thread "Thread-7" java.util.EmptyStackException
at java.util.Stack.peek(Stack.java:102)
at Utility.peekInt(Utility.java:26)
at Frame$repainter.run(Frame.java:72)
at java.lang.Thread.run(Thread.java:722)
4

2 回答 2

5

因为它不是线程安全的。假设堆栈中有一个元素,并且两个线程都在语句处if(integers.isEmpty()),这两个线程都将返回 false 并跳到下一个语句。现在,如果调用的线程nextInt()先调用integers.pop(),则将从堆栈中取出一个元素,并且堆栈将为空。现在,当调用的另一个线程peekInt()执行integers.peek()时,它会抛出,EmptyStackException因为堆栈中没有元素。

您可以做的是尝试同步方法nextInt()peekInt()同步之外refill(),如下所示:

private static synchronized int nextInt(){...}
public static synchronized int peekInt(){...}
于 2013-04-20T23:28:20.200 回答
2

您的代码不是线程安全的。考虑堆栈仅包含一个元素/整数的场景,并且在 nextInt() 和 peekInt() 方法中执行两个线程,两者都会看到堆栈非空,因此不调用 refill() 方法,现在如果一个线程在另一个线程调用 peek() 之前稍微执行 pop(),您将得到 StackEmptyException。

同步 nextInt() 和 peekInt() 将解决问题。

于 2013-04-20T23:29:12.513 回答