我有这个课程的一部分
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)
答案 0 :(得分: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(){...}
答案 1 :(得分:2)
您的代码不是线程安全的。考虑堆栈只包含一个元素/整数,并且在nextInt()和peekInt()方法中执行两个线程的场景,两者都会看到堆栈非空,因此不会调用refill()方法,现在如果有的话线程在另一个线程调用peek()之前稍微执行pop(),你将得到StackEmptyException。
同步nextInt()和peekInt()将解决问题。