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: 2008can 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()"); } }
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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.