我正在为OCPJP考试而学习,并且很难理解线程。特别是,我在下面列出了该程序。当我运行该程序时,得到以下输出,这使我感到困惑。
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()");
}
}
最佳答案
输出是一致的,但并不直接与堆栈上的操作相对应(对println
和pop
/ push
的单独调用不是原子的)。在Java中,不要在Thread.sleep(n)
中释放监视器上的锁是正确的(但是Object.wait()
并非如此)。
要查看实际订单,您可以修改放入堆栈的内容...
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();
现在,您应该能够看到哪个推送对应于哪个弹出。
关于java - Java线程同步意外输出,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/26311103/