0

I am studying for the OCPJP exam and having a hard time understanding threads. In particular, I have this program out lined below. When I run this program I get the following output and it is confusing me.

Inside push method...
Inside push method now sleeping...
Exit from main()
Inside push method stopped sleeping...
Exiting push method...
Pushed: true
Popped: 2008
Inside push method...
Inside push method now sleeping...
Inside push method stopped sleeping...
Exiting push method...
Pushed: true
Inside push method...
Inside push method now sleeping...
Inside push method stopped sleeping...
Exiting push method...
Pushed: true
Popped: 2008
Inside push method...
Inside push method now sleeping...
Popped: 2008

What is getting me is the last line of the output. The api says the thread does not lose ownership of any monitors/lock when sleep is called. How is it that the following:

Inside push method now sleeping...
Popped: 2008
can occur since the moment we enter the synchronized method push(), push() has the monitor/lock, why are we able execute the pop() method while the push() is sleeping? I need assistance, may someone please give an easy to understand explanation?

class StackImpl {                   //(1)


private Object[] stackArray;
private int topOfStack;

public StackImpl(int capacity){
    stackArray = new Object[capacity];
    topOfStack = -1;
}

//  public boolean push(Object element){                                    //(2a) non-synchronized
public synchronized boolean push(Object element){                   //(2b) synchronized
    if(isFull()) return false;
    System.out.println("Inside push method...");
    ++topOfStack;
    try{
        System.out.println("Inside push method now sleeping...");
        Thread.sleep(10000);
        System.out.println("Inside push method stopped sleeping...");} catch(Exception e){}                 //(3) Sleep a little
    stackArray[topOfStack] = element;
    System.out.println("Exiting push method...");
    return true;

}


//public Object pop(){                                              //(4a) non-synchronized
public synchronized Object pop(){                                   //(4b) synchronized
    if(isEmpty()) return null;
    Object obj = stackArray[topOfStack];
    stackArray[topOfStack] = null;
    try{Thread.sleep(1000);}catch(Exception e){}                        //(5) Sleep a little
    topOfStack--;
    return obj;

}

public boolean isEmpty(){return topOfStack < 0;}
public boolean isFull(){return topOfStack >= stackArray.length - 1;}


}


public class Mutex{
public static void main(String[] args) throws InterruptedException {

    final  StackImpl stack = new StackImpl(20);                     //(6) Shared by the threads

    (new Thread("Pusher"){                                          //(7) Thread no. 1  
        public void run(){
            for(;;){
                System.out.println("Pushed: " + stack.push(2008));
            }
        }
    }).start();

    // make sure Thread no.1 goes first
    Thread.sleep(2000);

    (new Thread("Popper"){                                          //(8) Thread no.2
        public void run(){
            for(;;){
                System.out.println("Popped: " + stack.pop());
            }
        }
    }).start();


    System.out.println("Exit from main()");



}
}

1 Answer 1

1

The output is consistent, but it doesn't directly correspond with operations on the stack (the separate calls to println and pop/push are not atomic). In Java, it is correct that you don't release the lock on the monitor in a Thread.sleep(n) (however it isn't true for Object.wait()).

To see the actual order, you can modify what is put onto the stack...

final  StackImpl stack = new StackImpl(20);                     //(6) Shared by the threads


(new Thread("Pusher"){                                          //(7) Thread no. 1

    public void run(){

    int i = 0;

        for(;;){
            System.out.println("Pushed: " + stack.push(i++));
        }
    }
}).start();

Now you should be able to see which push corresponds with which pop.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you Jason, I appreciate the help, I will give your solution a shot and see if I can understand it any better. I will come back and tell you if I do or don't.
The main point is that the call to println happens after a call to push or pop, but you can't say anything about the order between concurrent calls to println since you're only synchronizing within those two calls.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.