Josh Sobel
Josh Sobel

Reputation: 1328

StackEmptyException occuring when not expected

I have this part of a class

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

and two different threads call the methods nextInt and peekInt but sometimes they get a stack empty exception but why would that happen if they both call refill before getting their value.

here is the exception trace

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)

Upvotes: 0

Views: 133

Answers (2)

Suchet
Suchet

Reputation: 216

Your code is not thread safe. Consider the scenario where the stack contains only one element/integer, and two threads are executing in the nextInt() and peekInt() methods, both will see the stack is non empty and therefore refill() method is not called, now if one thread executes pop() slightly before the other thread calls peek(), you will get the StackEmptyException.

Synchronizing nextInt() and peekInt() will solve the problem.

Upvotes: 2

Eng.Fouad
Eng.Fouad

Reputation: 117665

Because it isn't thread-safe. Suppose the stack has one element in it and both threads are at the statement if(integers.isEmpty()), which both would return false and step over to the next statement. Now if the thread that invokes nextInt() goes first and calls integers.pop(), then the one element will be taken from the stack and the stack will be empty. Now when the other thread that invokes peekInt() executes integers.peek(), it will throw EmptyStackException since there are no elements in the stack.

What you can do is trying to synchronize the methods nextInt() and peekInt() beside synchronizing refill(), as follows:

private static synchronized int nextInt(){...}
public static synchronized int peekInt(){...}

Upvotes: 5

Related Questions