2014-10-11 80 views
0

我正在學習OCPJP考試,並且很難理解線程。特別是,我在下面列出了這個程序。當我運行這個程序時,我得到了下面的輸出,它讓我感到困惑。Java線程同步意外輸出

 
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 

得到我的是最後一行輸出。 api表示,在調用睡眠時,線程不會失去任何監視器/鎖的所有權。它是如何發生的:

Inside push method now sleeping... 
Popped: 2008
自從我們進入同步方法push(),push()具有監視器/鎖定時,可能會發生,爲什麼我們能夠在push()正在休眠時執行pop()方法?我需要幫助,可能有人請給出一個容易理解的解釋?

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

輸出是一致的,但它不直接與在堆棧上操作對應(單獨的調用printlnpop/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(); 

現在,你應該能夠看到這推動與流行對應。

+0

謝謝賈森,我很感激幫助,我會給你的解決方案一個鏡頭,看看我能否更好地理解它。我會回來告訴你,如果我做或不做。 – user1279734 2014-10-11 05:36:11

+0

重要的一點是調用'println'是在調用'push'或'pop'後發生的,但是你不能說對'println'的併發調用之間的順序,因爲你只在那些內部同步兩個電話。 – Jason 2014-10-11 05:51:02